""" DevWalker.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 direct.showbase.InputStateGlobal import inputState from direct.directnotify import DirectNotifyGlobal from direct.showbase import DirectObject from direct.task.Task import Task from panda3d.core import * class DevWalker(DirectObject.DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("DevWalker") wantDebugIndicator = ConfigVariableBool('want-avatar-physics-indicator', False) runMultiplier = ConfigVariableDouble('dev-run-multiplier', 4.0) # Ghost mode overrides this: slideName = "slide-is-disabled" # special methods def __init__(self): DirectObject.DirectObject.__init__(self) self.speed=0.0 self.rotationSpeed=0.0 self.slideSpeed=0.0 self.vel=Vec3(0.0, 0.0, 0.0) self.task = None 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, self.slideSpeed) def setAvatar(self, avatar): self.avatar = avatar if avatar is not None: pass # setup the avatar def setWallBitMask(self, bitMask): pass def setFloorBitMask(self, bitMask): pass def initializeCollisions(self, collisionTraverser, avatarNodePath, wallCollideMask, floorCollideMask, avatarRadius = 1.4, floorOffset = 1.0, reach = 1.0): assert not avatarNodePath.isEmpty() self.cTrav = collisionTraverser self.avatarNodePath = avatarNodePath def setAirborneHeightFunc(self, getAirborneHeight): pass def deleteCollisions(self): pass def setTag(self, key, value): pass def setCollisionsActive(self, active = 1): pass def placeOnFloor(self): pass def oneTimeCollide(self): pass def addBlastForce(self, vector): pass def displayDebugInfo(self): """ For debug use. """ onScreenDebug.add("w controls", "DevWalker") def handleAvatarControls(self, task): """ Check on the arrow keys and update the avatar. """ # get the button states: forward = inputState.isSet("forward") reverse = inputState.isSet("reverse") turnLeft = inputState.isSet("turnLeft") turnRight = inputState.isSet("turnRight") slideLeft = inputState.isSet("slideLeft") slideRight = inputState.isSet("slideRight") levitateUp = inputState.isSet("levitateUp") levitateDown = inputState.isSet("levitateDown") run = inputState.isSet("run") and self.runMultiplier.getValue() or 1.0 # Check for Auto-Run if base.localAvatar.getAutoRun(): forward = 1 reverse = 0 # Determine what the speeds are based on the buttons: self.speed=( (forward and self.avatarControlForwardSpeed or reverse and -self.avatarControlReverseSpeed)) self.liftSpeed=( (levitateUp and self.avatarControlForwardSpeed or levitateDown and -self.avatarControlReverseSpeed)) self.slideSpeed=( (slideLeft and -self.avatarControlForwardSpeed) or (slideRight and self.avatarControlForwardSpeed)) self.rotationSpeed=( (turnLeft and self.avatarControlRotateSpeed) or (turnRight and -self.avatarControlRotateSpeed)) if self.wantDebugIndicator: self.displayDebugInfo() # Check to see if we're moving at all: if self.speed or self.liftSpeed or self.slideSpeed or self.rotationSpeed: # How far did we move based on the amount of time elapsed? dt=ClockObject.getGlobalClock().getDt() distance = dt * self.speed * run lift = dt * self.liftSpeed * run slideDistance = dt * self.slideSpeed * run rotation = dt * self.rotationSpeed # Take a step in the direction of our previous heading. self.vel=Vec3(Vec3.forward() * distance + Vec3.up() * lift + Vec3.right() * slideDistance) if self.vel != Vec3.zero(): # rotMat is the rotation matrix corresponding to # our previous heading. rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up()) step=rotMat.xform(self.vel) self.avatarNodePath.setFluidPos(Point3(self.avatarNodePath.getPos()+step)) self.avatarNodePath.setH(self.avatarNodePath.getH()+rotation) messenger.send("avatarMoving") else: self.vel.set(0.0, 0.0, 0.0) return Task.cont def enableAvatarControls(self): """ Activate the arrow keys, etc. """ assert self.debugPrint("enableAvatarControls") if self.task: # remove any old self.task.remove(self.task) # spawn the new task self.task = taskMgr.add( self.handleAvatarControls, "AvatarControls-dev-%s"%(id(self),)) def disableAvatarControls(self): """ Ignore the arrow keys, etc. """ assert self.debugPrint("disableAvatarControls") if self.task: self.task.remove() self.task = None def flushEventHandlers(self): pass if __debug__: def debugPrint(self, message): """for debugging""" return self.notify.debug( str(id(self))+' '+message)