"""
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 messages 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 *
[docs]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
[docs] 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
[docs] def setWalkSpeed(self, forward, jump, reverse, rotate):
assert self.debugPrint("setWalkSpeed()")
self.avatarControlForwardSpeed=forward
#self.avatarControlJumpForce=jump
self.avatarControlReverseSpeed=reverse
self.avatarControlRotateSpeed=rotate
[docs] def getSpeeds(self):
#assert self.debugPrint("getSpeeds()")
return (self.speed, self.rotationSpeed, self.slideSpeed)
[docs] def setAvatar(self, avatar):
self.avatar = avatar
if avatar is not None:
pass # setup the avatar
[docs] def setWallBitMask(self, bitMask):
pass
[docs] def setFloorBitMask(self, bitMask):
pass
[docs] 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
[docs] def setAirborneHeightFunc(self, getAirborneHeight):
pass
[docs] def deleteCollisions(self):
pass
[docs] def setTag(self, key, value):
pass
[docs] def setCollisionsActive(self, active = 1):
pass
[docs] def placeOnFloor(self):
pass
[docs] def oneTimeCollide(self):
pass
[docs] def addBlastForce(self, vector):
pass
[docs] def displayDebugInfo(self):
"""
For debug use.
"""
onScreenDebug.add("w controls", "DevWalker")
[docs] 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
[docs] 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),))
[docs] def disableAvatarControls(self):
"""
Ignore the arrow keys, etc.
"""
assert self.debugPrint("disableAvatarControls")
if self.task:
self.task.remove()
self.task = None
[docs] def flushEventHandlers(self):
pass
if __debug__:
[docs] def debugPrint(self, message):
"""for debugging"""
return self.notify.debug(
str(id(self))+' '+message)