mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -04:00
moved from ../showbase
This commit is contained in:
parent
432390df8c
commit
59606cc4ec
196
direct/src/controls/ControlManager.py
Executable file
196
direct/src/controls/ControlManager.py
Executable file
@ -0,0 +1,196 @@
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
#from DirectGui import *
|
||||
#from PythonUtil import *
|
||||
#from IntervalGlobal import *
|
||||
|
||||
from otp.avatar import Avatar
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
#import GhostWalker
|
||||
#import GravityWalker
|
||||
#import NonPhysicsWalker
|
||||
#import PhysicsWalker
|
||||
#if __debug__:
|
||||
# import DevWalker
|
||||
from direct.task import Task
|
||||
|
||||
|
||||
class ControlManager:
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ControlManager")
|
||||
wantAvatarPhysicsIndicator = base.config.GetBool('want-avatar-physics-indicator', 0)
|
||||
wantAvatarPhysicsDebug = base.config.GetBool('want-avatar-physics-debug', 0)
|
||||
|
||||
def __init__(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.enableJumpCounter = 1
|
||||
self.controls = {}
|
||||
self.currentControls = None
|
||||
self.isEnabled = 1
|
||||
#self.monitorTask = taskMgr.add(self.monitor, "ControlManager-%s"%(id(self)), priority=-1)
|
||||
inputState.watch("forward", "arrow_up", "arrow_up-up")
|
||||
inputState.watch("forward", "control-arrow_up", "control-arrow_up-up")
|
||||
inputState.watch("forward", "alt-arrow_up", "alt-arrow_up-up")
|
||||
inputState.watch("forward", "shift-arrow_up", "shift-arrow_up-up")
|
||||
|
||||
inputState.watch("reverse", "arrow_down", "arrow_down-up")
|
||||
inputState.watch("reverse", "control-arrow_down", "control-arrow_down-up")
|
||||
inputState.watch("reverse", "alt-arrow_down", "alt-arrow_down-up")
|
||||
inputState.watch("reverse", "shift-arrow_down", "shift-arrow_down-up")
|
||||
|
||||
inputState.watch("turnLeft", "arrow_left", "arrow_left-up")
|
||||
inputState.watch("turnLeft", "control-arrow_left", "control-arrow_left-up")
|
||||
inputState.watch("turnLeft", "alt-arrow_left", "alt-arrow_left-up")
|
||||
inputState.watch("turnLeft", "shift-arrow_left", "shift-arrow_left-up")
|
||||
inputState.watch("turnLeft", "mouse-look_left", "mouse-look_left-done")
|
||||
|
||||
inputState.watch("turnRight", "arrow_right", "arrow_right-up")
|
||||
inputState.watch("turnRight", "control-arrow_right", "control-arrow_right-up")
|
||||
inputState.watch("turnRight", "alt-arrow_right", "alt-arrow_right-up")
|
||||
inputState.watch("turnRight", "shift-arrow_right", "shift-arrow_right-up")
|
||||
inputState.watch("turnRight", "mouse-look_right", "mouse-look_right-done")
|
||||
|
||||
inputState.watch("jump", "control", "control-up")
|
||||
inputState.watch("jump", "alt-control", "alt-control-up")
|
||||
inputState.watch("jump", "shift-control", "shift-control-up")
|
||||
|
||||
inputState.watch("slideLeft", "home", "home-up")
|
||||
inputState.watch("slideRight", "end", "end-up")
|
||||
inputState.watch("levitateUp", "page_up", "page_up-up")
|
||||
inputState.watch("levitateDown", "page_down", "page_down-up")
|
||||
inputState.watch("run", "shift", "shift-up")
|
||||
|
||||
# FYI, ghost mode uses jump for slide.
|
||||
#inputState.watch("slide", "slide-is-disabled", "slide-is-disabled")
|
||||
inputState.watch("slide", "mouse3", "mouse3-up")
|
||||
|
||||
#inputState.watch("slideLeft", "shift-arrow_left", "shift-arrow_left-up")
|
||||
#inputState.watch("slideLeft", "control-arrow_left", "control-arrow_left-up")
|
||||
#inputState.watch("slideLeft", "alt-arrow_left", "alt-arrow_left-up")
|
||||
#inputState.watch("slideLeft", "shift-arrow_left", "shift-arrow_left-up")
|
||||
#inputState.watch("slideLeft", "slide-is-disabled", "slide-is-disabled")
|
||||
|
||||
#inputState.watch("slideRight", "shift-arrow_right", "shift-arrow_right-up")
|
||||
#inputState.watch("slideRight", "control-arrow_right", "control-arrow_right-up")
|
||||
#inputState.watch("slideRight", "alt-arrow_right", "alt-arrow_right-up")
|
||||
#inputState.watch("slideRight", "shift-arrow_right", "shift-arrow_right-up")
|
||||
#inputState.watch("slideRight", "slide-is-disabled", "slide-is-disabled")
|
||||
|
||||
def add(self, controls, name="basic"):
|
||||
"""
|
||||
controls is an avatar control system.
|
||||
name is any key that you want to use to refer to the
|
||||
the controls later (e.g. using the use(<name>) call).
|
||||
|
||||
Add a control instance to the list of available control systems.
|
||||
|
||||
See also: use().
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
assert controls is not None
|
||||
oldControls = self.controls.get(name)
|
||||
if oldControls is not None:
|
||||
print "Replacing controls:", name
|
||||
oldControls.disableAvatarControls()
|
||||
oldControls.setCollisionsActive(0)
|
||||
oldControls.delete()
|
||||
controls.disableAvatarControls()
|
||||
controls.setCollisionsActive(0)
|
||||
self.controls[name] = controls
|
||||
|
||||
def use(self, name="basic"):
|
||||
"""
|
||||
name is a key (string) that was previously passed to add().
|
||||
|
||||
Use a previously added control system.
|
||||
|
||||
See also: add().
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
controls = self.controls.get(name)
|
||||
if controls is not None:
|
||||
if controls is not self.currentControls:
|
||||
if self.currentControls is not None:
|
||||
self.currentControls.disableAvatarControls()
|
||||
self.currentControls.setCollisionsActive(0)
|
||||
self.currentControls = controls
|
||||
self.currentControls.setCollisionsActive(1)
|
||||
if self.isEnabled:
|
||||
self.currentControls.enableAvatarControls()
|
||||
#else:
|
||||
# print "Controls are already", name
|
||||
else:
|
||||
print "Unkown controls:", name
|
||||
|
||||
def setSpeeds(self, forwardSpeed, jumpForce,
|
||||
reverseSpeed, rotateSpeed):
|
||||
assert self.notify.debugCall(id(self))
|
||||
for controls in self.controls.values():
|
||||
controls.setWalkSpeed(
|
||||
forwardSpeed, jumpForce, reverseSpeed, rotateSpeed)
|
||||
|
||||
def delete(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.disable()
|
||||
#self.monitorTask.remove()
|
||||
|
||||
def getSpeeds(self):
|
||||
return self.currentControls.getSpeeds()
|
||||
|
||||
def deleteCollisions(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
for controls in self.controls.values():
|
||||
controls.deleteCollisions()
|
||||
|
||||
def collisionsOn(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.currentControls.setCollisionsActive(1)
|
||||
|
||||
def collisionsOff(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.currentControls.setCollisionsActive(0)
|
||||
|
||||
def placeOnFloor(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.currentControls.placeOnFloor()
|
||||
|
||||
def enable(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.isEnabled = 1
|
||||
self.currentControls.enableAvatarControls()
|
||||
|
||||
def disable(self):
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.isEnabled = 0
|
||||
self.currentControls.disableAvatarControls()
|
||||
|
||||
def enableAvatarJump(self):
|
||||
"""
|
||||
Stop forcing the ctrl key to return 0's
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.enableJumpCounter+=1
|
||||
if self.enableJumpCounter:
|
||||
assert self.enableJumpCounter == 1
|
||||
self.enableJumpCounter = 1
|
||||
inputState.unforce("jump")
|
||||
|
||||
def disableAvatarJump(self):
|
||||
"""
|
||||
Force the ctrl key to return 0's
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
self.enableJumpCounter-=1
|
||||
if self.enableJumpCounter <= 0:
|
||||
inputState.force("jump", 0)
|
||||
|
||||
def monitor(self, foo):
|
||||
#assert(self.debugPrint("monitor()"))
|
||||
#if 1:
|
||||
# airborneHeight=self.avatar.getAirborneHeight()
|
||||
# onScreenDebug.add("airborneHeight", "% 10.4f"%(airborneHeight,))
|
||||
if 0:
|
||||
onScreenDebug.add("InputState forward", "%d"%(inputState.isSet("forward")))
|
||||
onScreenDebug.add("InputState reverse", "%d"%(inputState.isSet("reverse")))
|
||||
onScreenDebug.add("InputState turnLeft", "%d"%(inputState.isSet("turnLeft")))
|
||||
onScreenDebug.add("InputState turnRight", "%d"%(inputState.isSet("turnRight")))
|
||||
return Task.cont
|
161
direct/src/controls/DevWalker.py
Executable file
161
direct/src/controls/DevWalker.py
Executable file
@ -0,0 +1,161 @@
|
||||
"""
|
||||
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.ShowBaseGlobal import *
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase import DirectObject
|
||||
|
||||
class DevWalker(DirectObject.DirectObject):
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("DevWalker")
|
||||
wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator', 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.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)
|
||||
|
||||
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 setCollisionsActive(self, active = 1):
|
||||
pass
|
||||
|
||||
def placeOnFloor(self):
|
||||
pass
|
||||
|
||||
def oneTimeCollide(self):
|
||||
pass
|
||||
|
||||
def displayDebugInfo(self):
|
||||
"""
|
||||
For debug use.
|
||||
"""
|
||||
onScreenDebug.add("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 4.0 or 1.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
|
||||
|
||||
if __debug__:
|
||||
def debugPrint(self, message):
|
||||
"""for debugging"""
|
||||
return self.notify.debug(
|
||||
str(id(self))+' '+message)
|
27
direct/src/controls/GhostWalker.py
Executable file
27
direct/src/controls/GhostWalker.py
Executable file
@ -0,0 +1,27 @@
|
||||
"""
|
||||
GhostWalker.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.ShowBaseGlobal import *
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
import NonPhysicsWalker
|
||||
|
||||
class GhostWalker(NonPhysicsWalker.NonPhysicsWalker):
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("GhostWalker")
|
||||
|
||||
# Ghosts slide instead of jump:
|
||||
slideName = "jump"
|
614
direct/src/controls/GravityWalker.py
Executable file
614
direct/src/controls/GravityWalker.py
Executable file
@ -0,0 +1,614 @@
|
||||
"""
|
||||
GravityWalker.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.ShowBaseGlobal import *
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase import DirectObject
|
||||
from pandac import PhysicsManager
|
||||
import math
|
||||
|
||||
|
||||
class GravityWalker(DirectObject.DirectObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("GravityWalker")
|
||||
wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator', 0)
|
||||
wantFloorSphere = base.config.GetBool('want-floor-sphere', 0)
|
||||
|
||||
# special methods
|
||||
def __init__(self, gravity = -32.1740, standableGround=0.707,
|
||||
hardLandingForce=16.0):
|
||||
assert self.notify.debugStateCall(self)
|
||||
DirectObject.DirectObject.__init__(self)
|
||||
self.__gravity=gravity
|
||||
self.__standableGround=standableGround
|
||||
self.__hardLandingForce=hardLandingForce
|
||||
|
||||
self.mayJump = 1
|
||||
self.jumpDelayTask = None
|
||||
|
||||
self.controlsTask = None
|
||||
self.indicatorTask = None
|
||||
|
||||
self.falling = 0
|
||||
self.needToDeltaPos = 0
|
||||
self.physVelocityIndicator=None
|
||||
self.avatarControlForwardSpeed=0
|
||||
self.avatarControlJumpForce=0
|
||||
self.avatarControlReverseSpeed=0
|
||||
self.avatarControlRotateSpeed=0
|
||||
self.getAirborneHeight=None
|
||||
|
||||
self.priorParent=Vec3(0)
|
||||
self.__oldPosDelta=Vec3(0)
|
||||
self.__oldDt=0
|
||||
|
||||
self.moving=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 delete(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
if self.doLaterTask is not None:
|
||||
self.doLaterTask.remove()
|
||||
del self.doLaterTask
|
||||
#DirectObject.DirectObject.delete(self)
|
||||
|
||||
"""
|
||||
def spawnTest(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
if not self.wantDebugIndicator:
|
||||
return
|
||||
from pandac.PandaModules import *
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from toontown.coghq import MovingPlatform
|
||||
|
||||
if hasattr(self, "platform"):
|
||||
# Remove the prior instantiation:
|
||||
self.moveIval.pause()
|
||||
del self.moveIval
|
||||
self.platform.destroy()
|
||||
del self.platform
|
||||
self.platform2.destroy()
|
||||
del self.platform2
|
||||
|
||||
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("GravityWalker-spawnTest-%s"%fakeId)
|
||||
self.platformRoot.setPos(base.localAvatar, Vec3(0.0, 0.0, 1.0))
|
||||
self.platformRoot.setHpr(base.localAvatar, Vec3.zero())
|
||||
self.platform.reparentTo(self.platformRoot)
|
||||
|
||||
self.platform2 = MovingPlatform.MovingPlatform()
|
||||
self.platform2.setupCopyModel(1+fakeId, model, 'platformcollision')
|
||||
self.platform2Root = render.attachNewNode("GravityWalker-spawnTest2-%s"%fakeId)
|
||||
self.platform2Root.setPos(base.localAvatar, Vec3(-16.0, 30.0, 1.0))
|
||||
self.platform2Root.setHpr(base.localAvatar, Vec3.zero())
|
||||
self.platform2.reparentTo(self.platform2Root)
|
||||
|
||||
duration = 5
|
||||
self.moveIval = Parallel(
|
||||
Sequence(
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform, duration,
|
||||
Vec3(0.0, 30.0, 0.0),
|
||||
name='platformOut%s' % fakeId,
|
||||
fluid = 1),
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform, duration,
|
||||
Vec3(0.0, 0.0, 0.0),
|
||||
name='platformBack%s' % fakeId,
|
||||
fluid = 1),
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform, duration,
|
||||
Vec3(0.0, 0.0, 30.0),
|
||||
name='platformUp%s' % fakeId,
|
||||
fluid = 1),
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform, duration,
|
||||
Vec3(0.0, 0.0, 0.0),
|
||||
name='platformDown%s' % fakeId,
|
||||
fluid = 1),
|
||||
),
|
||||
Sequence(
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform2, duration,
|
||||
Vec3(0.0, -30.0, 0.0),
|
||||
name='platform2Out%s' % fakeId,
|
||||
fluid = 1),
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform2, duration,
|
||||
Vec3(0.0, 30.0, 30.0),
|
||||
name='platform2Back%s' % fakeId,
|
||||
fluid = 1),
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform2, duration,
|
||||
Vec3(0.0, -30.0, 0.0),
|
||||
name='platform2Up%s' % fakeId,
|
||||
fluid = 1),
|
||||
WaitInterval(0.3),
|
||||
LerpPosInterval(self.platform2, duration,
|
||||
Vec3(0.0, 0.0, 0.0),
|
||||
name='platformDown%s' % fakeId,
|
||||
fluid = 1),
|
||||
),
|
||||
name='platformIval%s' % fakeId,
|
||||
)
|
||||
self.moveIval.loop()
|
||||
"""
|
||||
|
||||
def setWalkSpeed(self, forward, jump, reverse, rotate):
|
||||
assert self.notify.debugStateCall(self)
|
||||
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, bitmask, floorOffset, reach):
|
||||
assert self.notify.debugStateCall(self)
|
||||
# This is a ray cast from your head down to detect floor polygons.
|
||||
# This ray start is arbitrarily high in the air. Feel free to use
|
||||
# a higher or lower value depending on whether you want an avatar
|
||||
# that is outside of the world to step up to the floor when they
|
||||
# get under valid floor:
|
||||
cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
|
||||
cRayNode = CollisionNode('GW.cRayNode')
|
||||
cRayNode.addSolid(cRay)
|
||||
self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
|
||||
cRayNode.setFromCollideMask(bitmask)
|
||||
cRayNode.setIntoCollideMask(BitMask32.allOff())
|
||||
|
||||
# set up floor collision mechanism
|
||||
self.lifter = CollisionHandlerGravity()
|
||||
self.lifter.setGravity(32.174 * 2.0)
|
||||
self.lifter.addInPattern("enter%in")
|
||||
self.lifter.addOutPattern("exit%in")
|
||||
self.lifter.setOffset(floorOffset)
|
||||
self.lifter.setReach(reach)
|
||||
|
||||
# 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.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
|
||||
|
||||
def setupWallSphere(self, bitmask, avatarRadius):
|
||||
"""
|
||||
Set up the collision sphere
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
# This is a sphere on the ground to detect collisions with
|
||||
# walls, but not the floor.
|
||||
self.avatarRadius = avatarRadius
|
||||
cSphere = CollisionSphere(0.0, 0.0, avatarRadius, avatarRadius)
|
||||
cSphereNode = CollisionNode('GW.cWallSphereNode')
|
||||
cSphereNode.addSolid(cSphere)
|
||||
cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
|
||||
|
||||
cSphereNode.setFromCollideMask(bitmask)
|
||||
cSphereNode.setIntoCollideMask(BitMask32.allOff())
|
||||
|
||||
# set up collision mechanism
|
||||
handler = CollisionHandlerPusher()
|
||||
#handler.setInPattern("pusher_enter%in")
|
||||
#handler.setOutPattern("pusher_exit%in")
|
||||
|
||||
handler.addCollider(cSphereNodePath, self.avatarNodePath)
|
||||
self.pusher = handler
|
||||
self.cWallSphereNodePath = cSphereNodePath
|
||||
|
||||
def setupEventSphere(self, bitmask, avatarRadius):
|
||||
"""
|
||||
Set up the collision sphere
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
# This is a sphere a little larger than the wall sphere to
|
||||
# trigger events.
|
||||
self.avatarRadius = avatarRadius
|
||||
cSphere = CollisionSphere(0.0, 0.0, avatarRadius-0.1, avatarRadius*1.04)
|
||||
# Mark it intangible just to emphasize its non-physical purpose.
|
||||
cSphere.setTangible(0)
|
||||
cSphereNode = CollisionNode('GW.cEventSphereNode')
|
||||
cSphereNode.addSolid(cSphere)
|
||||
cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
|
||||
|
||||
cSphereNode.setFromCollideMask(bitmask)
|
||||
cSphereNode.setIntoCollideMask(BitMask32.allOff())
|
||||
|
||||
# set up collision mechanism
|
||||
handler = CollisionHandlerEvent()
|
||||
handler.addInPattern("enter%in")
|
||||
handler.addOutPattern("exit%in")
|
||||
|
||||
self.event = handler
|
||||
self.cEventSphereNodePath = cSphereNodePath
|
||||
|
||||
def setupFloorSphere(self, bitmask, avatarRadius):
|
||||
"""
|
||||
Set up the collision sphere
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
# This is a tiny sphere concentric with the wallSphere to keep
|
||||
# us from slipping through floors.
|
||||
self.avatarRadius = avatarRadius
|
||||
cSphere = CollisionSphere(0.0, 0.0, avatarRadius, 0.01)
|
||||
cSphereNode = CollisionNode('GW.cFloorSphereNode')
|
||||
cSphereNode.addSolid(cSphere)
|
||||
cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
|
||||
|
||||
cSphereNode.setFromCollideMask(bitmask)
|
||||
cSphereNode.setIntoCollideMask(BitMask32.allOff())
|
||||
|
||||
# set up collision mechanism
|
||||
handler = CollisionHandlerPusher()
|
||||
#handler.setInPattern("pusherFloor_enter%in")
|
||||
#handler.setOutPattern("pusherFloor_exit%in")
|
||||
|
||||
handler.addCollider(cSphereNodePath, self.avatarNodePath)
|
||||
self.pusherFloor = handler
|
||||
self.cFloorSphereNodePath = cSphereNodePath
|
||||
|
||||
def initializeCollisions(self, collisionTraverser, avatarNodePath,
|
||||
wallBitmask, floorBitmask,
|
||||
avatarRadius = 1.4, floorOffset = 1.0, reach = 1.0):
|
||||
"""
|
||||
floorOffset is how high the avatar can reach. I.e. if the avatar
|
||||
walks under a ledge that is <= floorOffset above the ground (a
|
||||
double floor situation), the avatar will step up on to the
|
||||
ledge (instantly).
|
||||
|
||||
Set up the avatar collisions
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
|
||||
assert not avatarNodePath.isEmpty()
|
||||
self.avatarNodePath = avatarNodePath
|
||||
|
||||
self.cTrav = collisionTraverser
|
||||
|
||||
self.setupRay(floorBitmask, floorOffset, reach )
|
||||
self.setupWallSphere(wallBitmask, avatarRadius)
|
||||
self.setupEventSphere(wallBitmask, avatarRadius)
|
||||
if self.wantFloorSphere:
|
||||
self.setupFloorSphere(floorBitmask, avatarRadius)
|
||||
|
||||
self.setCollisionsActive(1)
|
||||
|
||||
def setAirborneHeightFunc(self, unused_parameter):
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.getAirborneHeight = self.lifter.getAirborneHeight
|
||||
|
||||
def getAirborneHeight(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.lifter.getAirborneHeight()
|
||||
|
||||
def setAvatarPhysicsIndicator(self, indicator):
|
||||
"""
|
||||
indicator is a NodePath
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.cWallSphereNodePath.show()
|
||||
|
||||
def deleteCollisions(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
del self.cTrav
|
||||
|
||||
self.cWallSphereNodePath.removeNode()
|
||||
del self.cWallSphereNodePath
|
||||
if self.wantFloorSphere:
|
||||
self.cFloorSphereNodePath.removeNode()
|
||||
del self.cFloorSphereNodePath
|
||||
|
||||
del self.pusher
|
||||
# del self.pusherFloor
|
||||
del self.event
|
||||
del self.lifter
|
||||
|
||||
del self.getAirborneHeight
|
||||
|
||||
def setCollisionsActive(self, active = 1):
|
||||
assert self.notify.debugStateCall(self)
|
||||
if self.collisionsActive != active:
|
||||
self.collisionsActive = active
|
||||
# Each time we change the collision geometry, make one
|
||||
# more pass to ensure we aren't standing in a wall.
|
||||
self.oneTimeCollide()
|
||||
if active:
|
||||
if 1:
|
||||
# Please let skyler or drose know if this is causing a problem
|
||||
# This is a bit of a hack fix:
|
||||
self.avatarNodePath.setP(0.0)
|
||||
self.avatarNodePath.setR(0.0)
|
||||
self.cTrav.addCollider(self.cWallSphereNodePath, self.pusher)
|
||||
if self.wantFloorSphere:
|
||||
self.cTrav.addCollider(self.cFloorSphereNodePath, self.pusherFloor)
|
||||
self.cTrav.addCollider(self.cEventSphereNodePath, self.event)
|
||||
self.cTrav.addCollider(self.cRayNodePath, self.lifter)
|
||||
else:
|
||||
self.cTrav.removeCollider(self.cWallSphereNodePath)
|
||||
if self.wantFloorSphere:
|
||||
self.cTrav.removeCollider(self.cFloorSphereNodePath)
|
||||
self.cTrav.removeCollider(self.cEventSphereNodePath)
|
||||
self.cTrav.removeCollider(self.cRayNodePath)
|
||||
|
||||
def getCollisionsActive(self):
|
||||
assert(self.debugPrint("getCollisionsActive() returning=%s"%(
|
||||
self.collisionsActive,)))
|
||||
return self.collisionsActive
|
||||
|
||||
def placeOnFloor(self):
|
||||
"""
|
||||
Make a reasonable effor to place the avatar on the ground.
|
||||
For example, this is useful when switching away from the
|
||||
current walker.
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.oneTimeCollide()
|
||||
self.avatarNodePath.setZ(self.avatarNodePath.getZ()-self.lifter.getAirborneHeight())
|
||||
|
||||
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.notify.debugStateCall(self)
|
||||
self.isAirborne = 0
|
||||
self.mayJump = 1
|
||||
tempCTrav = CollisionTraverser("oneTimeCollide")
|
||||
tempCTrav.addCollider(self.cWallSphereNodePath, self.pusher)
|
||||
if self.wantFloorSphere:
|
||||
tempCTrav.addCollider(self.cFloorSphereNodePath, self.event)
|
||||
tempCTrav.addCollider(self.cRayNodePath, self.lifter)
|
||||
tempCTrav.traverse(render)
|
||||
|
||||
def setMayJump(self, task):
|
||||
"""
|
||||
This function's use is internal to this class (maybe I'll add
|
||||
the __ someday). Anyway, if you want to enable or disable
|
||||
jumping in a general way see the ControlManager (don't use this).
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.mayJump = 1
|
||||
return Task.done
|
||||
|
||||
def startJumpDelay(self, delay):
|
||||
assert self.notify.debugStateCall(self)
|
||||
if self.jumpDelayTask:
|
||||
self.jumpDelayTask.remove()
|
||||
self.mayJump = 0
|
||||
self.jumpDelayTask=taskMgr.doMethodLater(
|
||||
delay,
|
||||
self.setMayJump,
|
||||
"jumpDelay-%s"%id(self))
|
||||
|
||||
def displayDebugInfo(self):
|
||||
"""
|
||||
For debug use.
|
||||
"""
|
||||
onScreenDebug.add("w controls", "GravityWalker")
|
||||
|
||||
onScreenDebug.add("w airborneHeight", self.lifter.getAirborneHeight())
|
||||
onScreenDebug.add("w falling", self.falling)
|
||||
onScreenDebug.add("w isOnGround", self.lifter.isOnGround())
|
||||
#onScreenDebug.add("w gravity", self.lifter.getGravity())
|
||||
#onScreenDebug.add("w jumpForce", self.avatarControlJumpForce)
|
||||
onScreenDebug.add("w contact normal", self.lifter.getContactNormal().pPrintValues())
|
||||
onScreenDebug.add("w mayJump", self.mayJump)
|
||||
onScreenDebug.add("w impact", self.lifter.getImpactVelocity())
|
||||
onScreenDebug.add("w velocity", self.lifter.getVelocity())
|
||||
onScreenDebug.add("w isAirborne", self.isAirborne)
|
||||
onScreenDebug.add("w hasContact", self.lifter.hasContact())
|
||||
|
||||
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")
|
||||
#slide = 0 #hack -- was: inputState.isSet("slide")
|
||||
slide = inputState.isSet("slide")
|
||||
jump = inputState.isSet("jump")
|
||||
# Determine what the speeds are based on the buttons:
|
||||
self.speed=(forward and self.avatarControlForwardSpeed or
|
||||
reverse and -self.avatarControlReverseSpeed)
|
||||
# Should fSlide be renamed slideButton?
|
||||
self.slideSpeed=slide and (
|
||||
(turnLeft and -self.avatarControlForwardSpeed) or
|
||||
(turnRight and self.avatarControlForwardSpeed))
|
||||
self.rotationSpeed=not slide and (
|
||||
(turnLeft and self.avatarControlRotateSpeed) or
|
||||
(turnRight and -self.avatarControlRotateSpeed))
|
||||
|
||||
if self.needToDeltaPos:
|
||||
self.setPriorParentVector()
|
||||
self.needToDeltaPos = 0
|
||||
if self.wantDebugIndicator:
|
||||
self.displayDebugInfo()
|
||||
if self.lifter.isOnGround():
|
||||
if self.isAirborne:
|
||||
self.isAirborne = 0
|
||||
assert(self.debugPrint("isAirborne 0 due to isOnGround() true"))
|
||||
impact = self.lifter.getImpactVelocity()
|
||||
if impact < -30.0:
|
||||
messenger.send("jumpHardLand")
|
||||
self.startJumpDelay(0.3)
|
||||
else:
|
||||
messenger.send("jumpLand")
|
||||
if impact < -5.0:
|
||||
self.startJumpDelay(0.2)
|
||||
# else, ignore the little potholes.
|
||||
assert(self.isAirborne == 0)
|
||||
self.priorParent = Vec3.zero()
|
||||
if jump and self.mayJump:
|
||||
# ...the jump button is down and we're close
|
||||
# enough to the ground to jump.
|
||||
self.lifter.addVelocity(self.avatarControlJumpForce)
|
||||
messenger.send("jumpStart")
|
||||
self.isAirborne = 1
|
||||
assert(self.debugPrint("isAirborne 1 due to jump"))
|
||||
else:
|
||||
if self.isAirborne == 0:
|
||||
assert(self.debugPrint("isAirborne 1 due to isOnGround() false"))
|
||||
self.isAirborne = 1
|
||||
|
||||
self.__oldPosDelta = self.avatarNodePath.getPosDelta(render)
|
||||
# How far did we move based on the amount of time elapsed?
|
||||
self.__oldDt = ClockObject.getGlobalClock().getDt()
|
||||
dt=self.__oldDt
|
||||
|
||||
# Check to see if we're moving at all:
|
||||
self.moving = self.speed or self.slideSpeed or self.rotationSpeed or (self.priorParent!=Vec3.zero())
|
||||
if self.moving:
|
||||
distance = dt * self.speed
|
||||
slideDistance = dt * self.slideSpeed
|
||||
rotation = dt * self.rotationSpeed
|
||||
|
||||
# Take a step in the direction of our previous heading.
|
||||
self.vel=Vec3(Vec3.forward() * distance +
|
||||
Vec3.right() * slideDistance)
|
||||
if self.vel != Vec3.zero() or self.priorParent != Vec3.zero():
|
||||
if 1:
|
||||
# rotMat is the rotation matrix corresponding to
|
||||
# our previous heading.
|
||||
rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
|
||||
step=rotMat.xform(self.vel) + (self.priorParent * dt)
|
||||
self.avatarNodePath.setFluidPos(Point3(
|
||||
self.avatarNodePath.getPos()+step))
|
||||
if 0:
|
||||
# rotMat is the rotation matrix corresponding to
|
||||
# our previous heading.
|
||||
rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), self.lifter.getContactNormal())
|
||||
step=rotMat.xform(self.vel) + (self.priorParent * dt)
|
||||
self.avatarNodePath.setFluidPos(Point3(
|
||||
self.avatarNodePath.getPos()+step))
|
||||
if 0:
|
||||
# rotMat is the rotation matrix corresponding to
|
||||
# our previous heading.
|
||||
rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
|
||||
forward = Vec3(rotMat.xform(Vec3.forward()))
|
||||
up = Vec3(rotMat.xform(self.lifter.getContactNormal()))
|
||||
rotMat2=Mat3()
|
||||
headsUp(rotMat2, forward, up)
|
||||
#rotMat2=Mat3.rotateMatNormaxis(0.0, )
|
||||
step=rotMat2.xform(self.vel) + (self.priorParent * dt)
|
||||
if 1:
|
||||
onScreenDebug.add("a getH()", self.avatarNodePath.getH())
|
||||
onScreenDebug.add("a forward", forward.pPrintValues())
|
||||
onScreenDebug.add("a up", up.pPrintValues())
|
||||
onScreenDebug.add("a Vec3.forward()", Vec3.forward().pPrintValues())
|
||||
onScreenDebug.add("a Vec3.up()", Vec3.up().pPrintValues())
|
||||
onScreenDebug.add("a Vec3.right()", Vec3.right().pPrintValues())
|
||||
onScreenDebug.add("a contactNormal()", self.lifter.getContactNormal().pPrintValues())
|
||||
onScreenDebug.add("a rotMat", rotMat.pPrintValues())
|
||||
onScreenDebug.add("a rotMat2", rotMat2.pPrintValues())
|
||||
self.avatarNodePath.setFluidPos(Point3(
|
||||
self.avatarNodePath.getPos()+step))
|
||||
self.avatarNodePath.setH(self.avatarNodePath.getH()+rotation)
|
||||
else:
|
||||
self.vel.set(0.0, 0.0, 0.0)
|
||||
if self.moving or jump:
|
||||
messenger.send("avatarMoving")
|
||||
return Task.cont
|
||||
|
||||
def doDeltaPos(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.needToDeltaPos = 1
|
||||
|
||||
def setPriorParentVector(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
if __debug__:
|
||||
onScreenDebug.add("__oldDt", "% 10.4f"%self.__oldDt)
|
||||
onScreenDebug.add("self.__oldPosDelta",
|
||||
self.__oldPosDelta.pPrintValues())
|
||||
velocity = self.__oldPosDelta*(1.0/self.__oldDt)
|
||||
self.priorParent = Vec3(velocity)
|
||||
if __debug__:
|
||||
if self.wantDebugIndicator:
|
||||
onScreenDebug.add("priorParent", self.priorParent.pPrintValues())
|
||||
|
||||
def reset(self):
|
||||
assert self.notify.debugStateCall(self)
|
||||
self.lifter.setVelocity(0.0)
|
||||
self.priorParent=Vec3.zero()
|
||||
|
||||
def enableAvatarControls(self):
|
||||
"""
|
||||
Activate the arrow keys, etc.
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
assert self.collisionsActive
|
||||
|
||||
#*#if __debug__:
|
||||
#*# self.accept("control-f3", self.spawnTest) #*#
|
||||
|
||||
# remove any old
|
||||
if self.controlsTask:
|
||||
self.controlsTask.remove()
|
||||
# spawn the new task
|
||||
taskName = "AvatarControls-%s"%(id(self),)
|
||||
self.controlsTask = taskMgr.add(self.handleAvatarControls, taskName, 25)
|
||||
|
||||
self.isAirborne = 0
|
||||
self.mayJump = 1
|
||||
|
||||
if self.physVelocityIndicator:
|
||||
if self.indicatorTask:
|
||||
self.indicatorTask.remove()
|
||||
self.indicatorTask = taskMgr.add(
|
||||
self.avatarPhysicsIndicator,
|
||||
"AvatarControlsIndicator-%s"%(id(self),), 35)
|
||||
|
||||
def disableAvatarControls(self):
|
||||
"""
|
||||
Ignore the arrow keys, etc.
|
||||
"""
|
||||
assert self.notify.debugStateCall(self)
|
||||
if self.controlsTask:
|
||||
self.controlsTask.remove()
|
||||
self.controlsTask = None
|
||||
if self.indicatorTask:
|
||||
self.indicatorTask.remove()
|
||||
self.indicatorTask = None
|
||||
if self.jumpDelayTask:
|
||||
self.jumpDelayTask.remove()
|
||||
self.jumpDelayTask = None
|
||||
|
||||
if __debug__:
|
||||
self.ignore("control-f3") #*#
|
||||
|
||||
|
||||
if __debug__:
|
||||
def debugPrint(self, message):
|
||||
"""for debugging"""
|
||||
return self.notify.debug(
|
||||
str(id(self))+' '+message)
|
94
direct/src/controls/InputState.py
Executable file
94
direct/src/controls/InputState.py
Executable file
@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase import DirectObject
|
||||
|
||||
|
||||
class InputState(DirectObject.DirectObject):
|
||||
"""
|
||||
InputState is for tracking the on/off state of some events.
|
||||
The initial usage is to watch some keyboard keys so that another
|
||||
task can poll the key states. By the way, in general polling is
|
||||
not a good idea, but it is useful in some situations. Know when
|
||||
to use it :) If in doubt, don't use this class and listen for
|
||||
events instead.
|
||||
"""
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("InputState")
|
||||
|
||||
def __init__(self):
|
||||
self.state = {}
|
||||
assert(self.debugPrint("InputState()"))
|
||||
self.watching = {}
|
||||
self.forcing = {}
|
||||
|
||||
def delete(self):
|
||||
self.ignoreAll()
|
||||
|
||||
def watch(self, name, eventOn, eventOff, default = 0):
|
||||
"""
|
||||
name is any string (or actually any valid dictionary key).
|
||||
eventOn is the string name of the Messenger event that will
|
||||
set the state (set to 1).
|
||||
eventOff is the string name of the Messenger event that will
|
||||
clear the state (set to 0).
|
||||
default is the initial value (this will be returned from
|
||||
isSet() if a call is made before any eventOn or eventOff
|
||||
events occur.
|
||||
See Also: ignore()
|
||||
"""
|
||||
assert(self.debugPrint(
|
||||
"watch(name=%s, eventOn=%s, eventOff=%s, default=%s)"%(
|
||||
name, eventOn, eventOff, default)))
|
||||
self.accept(eventOn, self.set, [name, 1])
|
||||
self.accept(eventOff, self.set, [name, 0])
|
||||
self.state[name] = default
|
||||
self.watching[name] = (eventOn, eventOff)
|
||||
|
||||
def force(self, name, value):
|
||||
"""
|
||||
Force isSet(name) to return value.
|
||||
See Also: unforce()
|
||||
"""
|
||||
self.forcing[name] = value
|
||||
|
||||
def unforce(self, name):
|
||||
"""
|
||||
Stop forcing a value.
|
||||
See Also: force()
|
||||
"""
|
||||
del self.forcing[name]
|
||||
|
||||
def ignore(self, name):
|
||||
"""
|
||||
The opposite of watch(name, ...)
|
||||
See Also: watch()
|
||||
"""
|
||||
eventOn, eventOff = self.watching[name]
|
||||
DirectObject.DirectObject.ignore(self, eventOn)
|
||||
DirectObject.DirectObject.ignore(self, eventOff)
|
||||
del self.watching[name]
|
||||
del self.state[name]
|
||||
|
||||
def set(self, name, isSet):
|
||||
assert(self.debugPrint("set(name=%s, isSet=%s)"%(name, isSet)))
|
||||
self.state[name] = isSet
|
||||
# We change the name befor sending it because this may
|
||||
# be the same name that messenger used to call InputState.set()
|
||||
# this avoids running in circles:
|
||||
messenger.send("InputState-%s"%(name,), [isSet])
|
||||
|
||||
def isSet(self, name):
|
||||
"""
|
||||
returns 0, 1, or None (if we're not tracking it at all)
|
||||
"""
|
||||
#assert(self.debugPrint("isSet(name=%s)"%(name)))
|
||||
r = self.forcing.get(name)
|
||||
if r is not None:
|
||||
return r
|
||||
return self.state.get(name)
|
||||
|
||||
def debugPrint(self, message):
|
||||
"""for debugging"""
|
||||
return self.notify.debug(
|
||||
"%s (%s) %s"%(id(self), len(self.state), message))
|
259
direct/src/controls/NonPhysicsWalker.py
Executable file
259
direct/src/controls/NonPhysicsWalker.py
Executable file
@ -0,0 +1,259 @@
|
||||
"""
|
||||
NonPhysicsWalker.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.ShowBaseGlobal import *
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase import DirectObject
|
||||
|
||||
class NonPhysicsWalker(DirectObject.DirectObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("NonPhysicsWalker")
|
||||
wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator', 0)
|
||||
|
||||
# Ghost mode overrides this:
|
||||
slideName = "slide-is-disabled"
|
||||
|
||||
# special methods
|
||||
def __init__(self):
|
||||
DirectObject.DirectObject.__init__(self)
|
||||
self.collisionsActive = 0
|
||||
self.speed=0.0
|
||||
self.rotationSpeed=0.0
|
||||
self.vel=Vec3(0.0, 0.0, 0.0)
|
||||
self.stopThisFrame = 0
|
||||
|
||||
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 initializeCollisions(self, collisionTraverser, avatarNodePath,
|
||||
wallCollideMask, floorCollideMask,
|
||||
avatarRadius = 1.4, floorOffset = 1.0, reach = 1.0):
|
||||
"""
|
||||
Set up the avatar for collisions
|
||||
"""
|
||||
assert not avatarNodePath.isEmpty()
|
||||
|
||||
self.cTrav = collisionTraverser
|
||||
self.avatarNodePath = avatarNodePath
|
||||
|
||||
# Set up the collision sphere
|
||||
# This is a sphere on the ground to detect barrier collisions
|
||||
self.cSphere = CollisionSphere(0.0, 0.0, 0.0, avatarRadius)
|
||||
cSphereNode = CollisionNode('NPW.cSphereNode')
|
||||
cSphereNode.addSolid(self.cSphere)
|
||||
self.cSphereNodePath = avatarNodePath.attachNewNode(cSphereNode)
|
||||
self.cSphereBitMask = wallCollideMask
|
||||
|
||||
cSphereNode.setFromCollideMask(self.cSphereBitMask)
|
||||
cSphereNode.setIntoCollideMask(BitMask32.allOff())
|
||||
|
||||
# Set up the collison ray
|
||||
# This is a ray cast from your head down to detect floor polygons.
|
||||
# This ray start is arbitrarily high in the air. Feel free to use
|
||||
# a higher or lower value depending on whether you want an avatar
|
||||
# that is outside of the world to step up to the floor when they
|
||||
# get under valid floor:
|
||||
self.cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
|
||||
cRayNode = CollisionNode('NPW.cRayNode')
|
||||
cRayNode.addSolid(self.cRay)
|
||||
self.cRayNodePath = avatarNodePath.attachNewNode(cRayNode)
|
||||
self.cRayBitMask = floorCollideMask
|
||||
cRayNode.setFromCollideMask(self.cRayBitMask)
|
||||
cRayNode.setIntoCollideMask(BitMask32.allOff())
|
||||
|
||||
# set up wall collision mechanism
|
||||
self.pusher = CollisionHandlerPusher()
|
||||
self.pusher.setInPattern("enter%in")
|
||||
self.pusher.setOutPattern("exit%in")
|
||||
|
||||
# set up floor collision mechanism
|
||||
self.lifter = CollisionHandlerFloor()
|
||||
self.lifter.setInPattern("on-floor")
|
||||
self.lifter.setOutPattern("off-floor")
|
||||
self.lifter.setOffset(floorOffset)
|
||||
self.lifter.setReach(reach)
|
||||
|
||||
# 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.pusher.addCollider(self.cSphereNodePath, avatarNodePath)
|
||||
self.lifter.addCollider(self.cRayNodePath, avatarNodePath)
|
||||
|
||||
# activate the collider with the traverser and pusher
|
||||
self.setCollisionsActive(1)
|
||||
|
||||
def setAirborneHeightFunc(self, getAirborneHeight):
|
||||
self.getAirborneHeight = getAirborneHeight
|
||||
|
||||
def deleteCollisions(self):
|
||||
del self.cTrav
|
||||
|
||||
del self.cSphere
|
||||
self.cSphereNodePath.removeNode()
|
||||
del self.cSphereNodePath
|
||||
|
||||
del self.cRay
|
||||
self.cRayNodePath.removeNode()
|
||||
del self.cRayNodePath
|
||||
|
||||
del self.pusher
|
||||
del self.lifter
|
||||
|
||||
def setCollisionsActive(self, active = 1):
|
||||
assert(self.debugPrint("setCollisionsActive(active%s)"%(active,)))
|
||||
if self.collisionsActive != active:
|
||||
self.collisionsActive = active
|
||||
if active:
|
||||
self.cTrav.addCollider(self.cSphereNodePath, self.pusher)
|
||||
self.cTrav.addCollider(self.cRayNodePath, self.lifter)
|
||||
else:
|
||||
self.cTrav.removeCollider(self.cSphereNodePath)
|
||||
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 placeOnFloor(self):
|
||||
"""
|
||||
Make a reasonable effor to place the avatar on the ground.
|
||||
For example, this is useful when switching away from the
|
||||
current walker.
|
||||
"""
|
||||
# With these on, getAirborneHeight is not returning the correct value so
|
||||
# when we open our book while swimming we pop down underneath the ground
|
||||
# self.oneTimeCollide()
|
||||
# self.avatarNodePath.setZ(self.avatarNodePath.getZ()-self.getAirborneHeight())
|
||||
# Since this is the non physics walker - wont they already be on the ground?
|
||||
return
|
||||
|
||||
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.
|
||||
"""
|
||||
tempCTrav = CollisionTraverser("oneTimeCollide")
|
||||
tempCTrav.addCollider(self.cSphereNodePath, self.pusher)
|
||||
tempCTrav.addCollider(self.cRayNodePath, self.lifter)
|
||||
tempCTrav.traverse(render)
|
||||
|
||||
def displayDebugInfo(self):
|
||||
"""
|
||||
For debug use.
|
||||
"""
|
||||
onScreenDebug.add("controls", "NonPhysicsWalker")
|
||||
|
||||
def handleAvatarControls(self, task):
|
||||
"""
|
||||
Check on the arrow keys and update the avatar.
|
||||
"""
|
||||
if not self.lifter.hasContact():
|
||||
# hack fix for falling through the floor:
|
||||
messenger.send("walkerIsOutOfWorld", [self.avatarNodePath])
|
||||
|
||||
# get the button states:
|
||||
forward = inputState.isSet("forward")
|
||||
reverse = inputState.isSet("reverse")
|
||||
turnLeft = inputState.isSet("turnLeft")
|
||||
turnRight = inputState.isSet("turnRight")
|
||||
slide = inputState.isSet(self.slideName) or 0
|
||||
#jump = inputState.isSet("jump")
|
||||
# Determine what the speeds are based on the buttons:
|
||||
self.speed=(forward and self.avatarControlForwardSpeed or
|
||||
reverse and -self.avatarControlReverseSpeed)
|
||||
# Should fSlide be renamed slideButton?
|
||||
self.slideSpeed=slide and (
|
||||
(turnLeft and -self.avatarControlForwardSpeed) or
|
||||
(turnRight and self.avatarControlForwardSpeed))
|
||||
self.rotationSpeed=not slide and (
|
||||
(turnLeft and self.avatarControlRotateSpeed) or
|
||||
(turnRight and -self.avatarControlRotateSpeed))
|
||||
|
||||
if self.wantDebugIndicator:
|
||||
self.displayDebugInfo()
|
||||
# How far did we move based on the amount of time elapsed?
|
||||
dt=ClockObject.getGlobalClock().getDt()
|
||||
# Check to see if we're moving at all:
|
||||
if self.speed or self.slideSpeed or self.rotationSpeed:
|
||||
if self.stopThisFrame:
|
||||
distance = 0.0
|
||||
slideDistance = 0.0
|
||||
rotation = 0.0
|
||||
self.stopThisFrame = 0
|
||||
else:
|
||||
distance = dt * self.speed
|
||||
slideDistance = dt * self.slideSpeed
|
||||
rotation = dt * self.rotationSpeed
|
||||
|
||||
# Take a step in the direction of our previous heading.
|
||||
self.vel=Vec3(Vec3.forward() * distance +
|
||||
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 doDeltaPos(self):
|
||||
assert(self.debugPrint("doDeltaPos()"))
|
||||
|
||||
def reset(self):
|
||||
assert(self.debugPrint("reset()"))
|
||||
|
||||
def enableAvatarControls(self):
|
||||
"""
|
||||
Activate the arrow keys, etc.
|
||||
"""
|
||||
assert(self.debugPrint("enableAvatarControls"))
|
||||
assert self.collisionsActive
|
||||
|
||||
taskName = "AvatarControls-%s"%(id(self),)
|
||||
# remove any old
|
||||
taskMgr.remove(taskName)
|
||||
# spawn the new task
|
||||
taskMgr.add(self.handleAvatarControls, taskName)
|
||||
|
||||
def disableAvatarControls(self):
|
||||
"""
|
||||
Ignore the arrow keys, etc.
|
||||
"""
|
||||
assert(self.debugPrint("disableAvatarControls"))
|
||||
taskName = "AvatarControls-%s"%(id(self),)
|
||||
taskMgr.remove(taskName)
|
||||
|
||||
if __debug__:
|
||||
def debugPrint(self, message):
|
||||
"""for debugging"""
|
||||
return self.notify.debug(
|
||||
str(id(self))+' '+message)
|
2
direct/src/controls/PhysicsRoller.py
Executable file
2
direct/src/controls/PhysicsRoller.py
Executable file
@ -0,0 +1,2 @@
|
||||
"""PhysicsRoller is for wheels, soccer balls, billiard balls, and other things that roll."""
|
||||
|
741
direct/src/controls/PhysicsWalker.py
Executable file
741
direct/src/controls/PhysicsWalker.py
Executable file
@ -0,0 +1,741 @@
|
||||
"""
|
||||
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 direct.showbase.ShowBaseGlobal import *
|
||||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.showbase import DirectObject
|
||||
from pandac 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 pandac.PandaModules import *
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from toontown.coghq 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(base.localAvatar, Vec3(0.0, 3.0, 1.0))
|
||||
self.platformRoot.setHpr(base.localAvatar, 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, CollisionHandlerRayStart, 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 0 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, reach = 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 0 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
|
||||
|
||||
del self.getAirborneHeight
|
||||
|
||||
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 placeOnFloor(self):
|
||||
"""
|
||||
Make a reasonable effort to place the avatar on the ground.
|
||||
For example, this is useful when switching away from the
|
||||
current walker.
|
||||
"""
|
||||
self.oneTimeCollide()
|
||||
self.avatarNodePath.setZ(self.avatarNodePath.getZ()-self.getAirborneHeight())
|
||||
|
||||
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("oneTimeCollide")
|
||||
if self.useHeightRay:
|
||||
if self.useLifter:
|
||||
tempCTrav.addCollider(self.cRayNodePath, self.lifter)
|
||||
else:
|
||||
tempCTrav.addCollider(self.cRayNodePath, self.cRayQueue)
|
||||
tempCTrav.traverse(render)
|
||||
|
||||
def handleAvatarControls(self, task):
|
||||
"""
|
||||
Check on the arrow keys and update the avatar.
|
||||
"""
|
||||
if __debug__:
|
||||
if self.wantAvatarPhysicsIndicator:
|
||||
onScreenDebug.append("localAvatar pos = %s\n"%(base.localAvatar.getPos().pPrintValues(),))
|
||||
onScreenDebug.append("localAvatar h = % 10.4f\n"%(base.localAvatar.getH(),))
|
||||
onScreenDebug.append("localAvatar anim = %s\n"%(base.localAvatar.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:
|
||||
# DCR: don't reset X and Y; allow player to move
|
||||
self.reset()
|
||||
self.avatarNodePath.setZ(50.0)
|
||||
messenger.send("walkerIsOutOfWorld", [self.avatarNodePath])
|
||||
|
||||
# get the button states:
|
||||
forward = inputState.isSet("forward")
|
||||
reverse = inputState.isSet("reverse")
|
||||
turnLeft = inputState.isSet("turnLeft")
|
||||
turnRight = inputState.isSet("turnRight")
|
||||
slide = 0#inputState.isSet("slide")
|
||||
slideLeft = 0#inputState.isSet("slideLeft")
|
||||
slideRight = 0#inputState.isSet("slideRight")
|
||||
jump = inputState.isSet("jump")
|
||||
# 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))
|
||||
|
||||
# How far did we move based on the amount of time elapsed?
|
||||
dt=ClockObject.getGlobalClock().getDt()
|
||||
|
||||
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 changing 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=LRotationf()
|
||||
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 reset(self):
|
||||
assert(self.debugPrint("reset()"))
|
||||
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()"))
|
||||
assert self.collisionsActive
|
||||
|
||||
if __debug__:
|
||||
#self.accept("control-f3", self.spawnTest) #*#
|
||||
self.accept("f3", self.reset) # 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()"))
|
||||
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)
|
0
direct/src/controls/Sources.pp
Normal file
0
direct/src/controls/Sources.pp
Normal file
0
direct/src/controls/__init__.py
Normal file
0
direct/src/controls/__init__.py
Normal file
Loading…
x
Reference in New Issue
Block a user