diff --git a/direct/src/showbase/ControlManager.py b/direct/src/showbase/ControlManager.py index dedc5a0be6..6226e74592 100755 --- a/direct/src/showbase/ControlManager.py +++ b/direct/src/showbase/ControlManager.py @@ -6,6 +6,7 @@ from ShowBaseGlobal import * import Avatar import DirectNotifyGlobal +import GhostWalker import GravityWalker import NonPhysicsWalker import PhysicsWalker @@ -21,7 +22,10 @@ class ControlManager: def __init__(self, avatar): self.avatar = avatar assert(self.debugPrint("ControlManager()")) - self.swimControls=NonPhysicsWalker.NonPhysicsWalker() + self.swimControls=GravityWalker.GravityWalker( + gravity = -32.1740 * 2.0) + #self.swimControls=NonPhysicsWalker.NonPhysicsWalker() + self.ghostControls=GhostWalker.GhostWalker() if self.wantAvatarPhysics: self.walkControls=GravityWalker.GravityWalker( gravity = -32.1740 * 2.0) # * 2.0 is a hack; @@ -57,6 +61,7 @@ class ControlManager: inputState.watch("jump", "alt-control", "alt-control-up") inputState.watch("jump", "shift-control", "shift-control-up") + # FYI, ghost mode uses jump for slide. inputState.watch("slide", "slide-is-disabled", "slide-is-disabled") #inputState.watch("slideLeft", "shift-arrow_left", "shift-arrow_left-up") @@ -71,6 +76,24 @@ class ControlManager: #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 = self.controls.get(name) + if controls is not None: + print "Replacing controls:", name + controls.delete() + self.controls[name] = controls + + def use(self, name="basic"): + controls = self.controls.get(name) + if controls is not None: + if controls is not self.currentControls: + self.currentControls.disableAvatarControls() + self.currentControls.setCollisionsActive(0) + self.currentControls = controls + self.currentControls.setCollisionsActive(1) + else: + print "Unkown controls:", name + def useSwimControls(self): assert(self.debugPrint("useSwimControls()")) if self.currentControls is not self.swimControls: @@ -81,6 +104,16 @@ class ControlManager: if self.isEnabled: self.currentControls.enableAvatarControls() + def useGhostControls(self): + assert(self.debugPrint("useGhostControls()")) + if self.currentControls is not self.ghostControls: + self.currentControls.disableAvatarControls() + self.currentControls.setCollisionsActive(0) + self.ghostControls.setCollisionsActive(1) + self.currentControls = self.ghostControls + if self.isEnabled: + self.currentControls.enableAvatarControls() + def useWalkControls(self): assert(self.debugPrint("useWalkControls()")) if self.currentControls is not self.walkControls: @@ -106,6 +139,11 @@ class ControlManager: toonJumpForce, toonReverseSpeed, toonRotateSpeed) + self.ghostControls.setWalkSpeed( + toonForwardSpeed, + toonJumpForce, + toonReverseSpeed, + toonRotateSpeed) self.walkControls.setWalkSpeed( toonForwardSpeed, toonJumpForce, @@ -116,7 +154,7 @@ class ControlManager: return self.currentControls.getSpeeds() def initializeCollisions(self, cTrav, - wallBitmask, floorBitmask, avatarRadius, floorOffset): + wallBitmask, floorBitmask, ghostBitMask, avatarRadius, floorOffset): assert(self.debugPrint("initializeCollisions()")) self.walkControls.initializeCollisions(cTrav, self.avatar, @@ -130,6 +168,12 @@ class ControlManager: self.swimControls.setAirborneHeightFunc(self.avatar.getAirborneHeight) self.swimControls.disableAvatarControls() self.swimControls.setCollisionsActive(0) + + self.ghostControls.initializeCollisions(cTrav, self.avatar, + ghostBitMask, floorBitmask, avatarRadius, floorOffset) + self.ghostControls.setAirborneHeightFunc(self.avatar.getAirborneHeight) + self.ghostControls.disableAvatarControls() + self.ghostControls.setCollisionsActive(0) self.walkControls.setCollisionsActive(1) self.walkControls.enableAvatarControls() @@ -138,6 +182,7 @@ class ControlManager: assert(self.debugPrint("deleteCollisions()")) self.walkControls.deleteCollisions() self.swimControls.deleteCollisions() + self.ghostControls.deleteCollisions() def collisionsOn(self): assert(self.debugPrint("collisionsOn()")) diff --git a/direct/src/showbase/GhostWalker.py b/direct/src/showbase/GhostWalker.py index bd3990a4b9..5f98c7ede9 100755 --- a/direct/src/showbase/GhostWalker.py +++ b/direct/src/showbase/GhostWalker.py @@ -23,53 +23,5 @@ class GhostWalker(NonPhysicsWalker.NonPhysicsWalker): notify = DirectNotifyGlobal.directNotify.newCategory("GhostWalker") - 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") - # Ghosts slide instead of jump: - slide = 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)) - - # How far did we move based on the amount of time elapsed? - dt=min(ClockObject.getGlobalClock().getDt(), 0.1) - # 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 + # Ghosts slide instead of jump: + slideName = "jump" diff --git a/direct/src/showbase/GravityWalker.py b/direct/src/showbase/GravityWalker.py index 5368c5dc6e..d3215d42f0 100755 --- a/direct/src/showbase/GravityWalker.py +++ b/direct/src/showbase/GravityWalker.py @@ -39,6 +39,11 @@ class GravityWalker(DirectObject.DirectObject): self.mayJump = 1 self.jumpDelayTask = None + + self.controlsTask = None + self.fixCliffTask = None + self.indicatorTask = None + self.falling = 0 self.needToDeltaPos = 0 self.physVelocityIndicator=None @@ -149,7 +154,7 @@ class GravityWalker(DirectObject.DirectObject): """ # This is a sphere on the ground to detect barrier collisions self.avatarRadius = avatarRadius - self.cSphere = CollisionSphere(0.0, 0.0, avatarRadius, avatarRadius) + self.cSphere = CollisionSphere(0.0, 0.0, avatarRadius+0.5, avatarRadius) cSphereNode = CollisionNode('GW.cWallSphereNode') cSphereNode.addSolid(self.cSphere) cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) @@ -159,8 +164,8 @@ class GravityWalker(DirectObject.DirectObject): # set up collision mechanism handler = CollisionHandlerPusher() - handler.setInPattern("enter%in") - handler.setOutPattern("exit%in") + handler.setInPattern("pusher_enter%in") + handler.setOutPattern("pusher_exit%in") handler.addCollider(cSphereNodePath, self.avatarNodePath) self.pusher = handler @@ -172,7 +177,7 @@ class GravityWalker(DirectObject.DirectObject): """ # This is a sphere on the ground to detect barrier collisions self.avatarRadius = avatarRadius - self.cSphere = CollisionSphere(0.0, 0.0, avatarRadius-0.1, avatarRadius) + self.cSphere = CollisionSphere(0.0, 0.0, avatarRadius-0.1, avatarRadius*1.04) cSphereNode = CollisionNode('GW.cFloorSphereNode') cSphereNode.addSolid(self.cSphere) cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) @@ -204,7 +209,7 @@ class GravityWalker(DirectObject.DirectObject): self.setupRay(floorBitmask, self.floorOffset) self.setupWallSphere(wallBitmask, avatarRadius) - self.setupFloorSphere(floorBitmask, avatarRadius) + self.setupFloorSphere(wallBitmask|floorBitmask, avatarRadius) self.setCollisionsActive(1) @@ -236,6 +241,9 @@ class GravityWalker(DirectObject.DirectObject): assert(self.debugPrint("collisionsActive(active=%s)"%(active,))) 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: self.cTrav.addCollider(self.cWallSphereNodePath, self.pusher) self.cTrav.addCollider(self.cFloorSphereNodePath, self.event) @@ -244,15 +252,25 @@ class GravityWalker(DirectObject.DirectObject): self.cTrav.removeCollider(self.cWallSphereNodePath) self.cTrav.removeCollider(self.cFloorSphereNodePath) 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 FixCliff(self, task): + """ + People are still making polygons that are marked + as floor, but are nearly vertical. This ray is + a hack to help deal with the cliff. + """ + if self.lifter.isInOuterSpace(): + temp = self.cRayNodePath.getZ() + self.cRayNodePath.setZ(14.0) + self.oneTimeCollide() + self.cRayNodePath.setZ(temp) + return Task.cont + def oneTimeCollide(self): """ Makes one quick collision pass for the avatar, for instance as @@ -294,7 +312,7 @@ class GravityWalker(DirectObject.DirectObject): reverse = inputState.isSet("reverse") turnLeft = inputState.isSet("turnLeft") turnRight = inputState.isSet("turnRight") - slide = inputState.isSet("slide") + slide = 0 #hack -- was: inputState.isSet("slide") jump = inputState.isSet("jump") pie = inputState.isSet("pie") # Determine what the speeds are based on the buttons: @@ -328,6 +346,8 @@ class GravityWalker(DirectObject.DirectObject): onScreenDebug.add("velocity", self.lifter.getVelocity()) #*# onScreenDebug.add("isAirborne", self.isAirborne) #*# onScreenDebug.add("jump", jump) #*# + + onScreenDebug.add("inOuterSpace", self.lifter.isInOuterSpace()) #*# if self.lifter.isOnGround(): if self.isAirborne: self.isAirborne = 0 @@ -408,13 +428,26 @@ class GravityWalker(DirectObject.DirectObject): if __debug__: self.accept("control-f3", self.spawnTest) #*# - taskName = "AvatarControls%s"%(id(self),) # remove any old - taskMgr.remove(taskName) + if self.controlsTask: + self.controlsTask.remove() # spawn the new task - taskMgr.add(self.handleAvatarControls, taskName, 25) + taskName = "AvatarControls%s"%(id(self),) + self.controlsTask = taskMgr.add(self.handleAvatarControls, taskName, 25) + + # remove any old + if self.fixCliffTask: + self.fixCliffTask.remove() + # spawn the new task + taskName = "AvatarControls-FixCliff%s"%(id(self),) + self.fixCliffTask = taskMgr.add(self.FixCliff, taskName, 31) + if self.physVelocityIndicator: - taskMgr.add(self.avatarPhysicsIndicator, "AvatarControlsIndicator%s"%(id(self),), 35) + if self.indicatorTask: + self.indicatorTask.remove() + self.indicatorTask = taskMgr.add( + self.avatarPhysicsIndicator, + "AvatarControlsIndicator%s"%(id(self),), 35) def disableAvatarControls(self): """ @@ -422,11 +455,15 @@ class GravityWalker(DirectObject.DirectObject): """ assert(self.debugPrint("disableAvatarControls()")) print id(self), "GW.disableAvatarControls()" - taskName = "AvatarControls%s"%(id(self),) - taskMgr.remove(taskName) - - taskName = "AvatarControlsIndicator%s"%(id(self),) - taskMgr.remove(taskName) + if self.controlsTask: + self.controlsTask.remove() + self.controlsTask = None + if self.fixCliffTask: + self.fixCliffTask.remove() + self.fixCliffTask = None + if self.indicatorTask: + self.indicatorTask.remove() + self.indicatorTask = None if __debug__: self.ignore("control-f3") #*# diff --git a/direct/src/showbase/NonPhysicsWalker.py b/direct/src/showbase/NonPhysicsWalker.py index b4561002f7..9e9d7111bd 100755 --- a/direct/src/showbase/NonPhysicsWalker.py +++ b/direct/src/showbase/NonPhysicsWalker.py @@ -23,6 +23,9 @@ class NonPhysicsWalker(DirectObject.DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("NonPhysicsWalker") + # Ghost mode overrides this: + slideName = "slide-is-disabled" + # special methods def __init__(self): DirectObject.DirectObject.__init__(self) @@ -151,7 +154,7 @@ class NonPhysicsWalker(DirectObject.DirectObject): reverse = inputState.isSet("reverse") turnLeft = inputState.isSet("turnLeft") turnRight = inputState.isSet("turnRight") - slide = inputState.isSet("slide") + slide = inputState.isSet(self.slideName) #jump = inputState.isSet("jump") # Determine what the speeds are based on the buttons: self.speed=(forward and self.avatarControlForwardSpeed or