diff --git a/direct/src/controls/ShipPilot2.py b/direct/src/controls/ShipPilot2.py new file mode 100755 index 0000000000..da9a794254 --- /dev/null +++ b/direct/src/controls/ShipPilot2.py @@ -0,0 +1,1104 @@ +""" +ShipPilot.py is for avatars pilotting ships (or more accurately, a ship +as the avatar). + +A 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 control events. +""" + +from direct.showbase.ShowBaseGlobal import * + +from direct.directnotify.DirectNotifyGlobal import directNotify +from pandac.PandaModules import PhysicsManager +import math + +from PhysicsWalker import PhysicsWalker + +class ShipPilot2(PhysicsWalker): + + notify = directNotify.newCategory("PhysicsWalker") + wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator', 0) + + useBowSternSpheres = 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)) + PhysicsWalker.__init__( + self, gravity, standableGround, hardLandingForce) + 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 + self.ship = None + + def setWalkSpeed(self, forward, jump, reverse, rotate): + assert(self.debugPrint("setWalkSpeed()")) + self.avatarControlForwardSpeed=forward + self.avatarControlJumpForce=0.0 + self.avatarControlReverseSpeed=reverse + self.avatarControlRotateSpeed=rotate + + def getSpeeds(self): + #assert(self.debugPrint("getSpeeds()")) + return (self.__speed, self.__rotationSpeed) + + def setAvatar(self, ship): + if ship is None: + self.takedownPhysics() + self.ship = None + else: + #self.setupShip() + self.setupPhysics(ship) + self.ship = ship + + #*# Debug: + if not hasattr(ship, "acceleration"): + self.ship.acceleration = 60 + self.ship.maxSpeed = 14 + self.ship.reverseAcceleration = 10 + self.ship.maxReverseSpeed = 2 + self.ship.turnRate = 3 + self.ship.maxTurn = 30 + self.ship.anchorDrag = .9 + self.ship.hullDrag = .9 + + 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( + #spammy --> "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 + if 0: + self.avatarRadius = avatarRadius + self.cSphere = CollisionTube( + Point3(0.0, 0.0, 0.0), Point3(0.0, 40.0, 0.0), avatarRadius) + cSphereNode = CollisionNode('SP.cSphereNode') + cSphereNode.addSolid(self.cSphere) + self.cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) + self.cSphereBitMask = bitmask + else: + # Middle sphere: + self.avatarRadius = avatarRadius + #self.cSphere = CollisionSphere(0.0, -5.0, 0.0, avatarRadius) + #cSphereNode = CollisionNode('SP.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) + + if self.useBowSternSpheres: + # Front sphere: + self.cBowSphere = CollisionSphere( + 0.0, self.frontSphereOffset, -5.0, avatarRadius) + cBowSphereNode = CollisionNode('SP.cBowSphereNode') + cBowSphereNode.addSolid(self.cBowSphere) + self.cBowSphereNodePath = self.avatarNodePath.attachNewNode( + cBowSphereNode) + + cBowSphereNode.setFromCollideMask(self.cSphereBitMask) + cBowSphereNode.setIntoCollideMask(BitMask32.allOff()) + + self.cBowSphereNode = cBowSphereNode + + self.pusher.addCollider( + self.cBowSphereNodePath, self.avatarNodePath) + + # Back sphere: + self.cSternSphere = CollisionSphere( + 0.0, self.backSphereOffset, -5.0, avatarRadius) + cSternSphereNode = CollisionNode('SP.cSternSphereNode') + cSternSphereNode.addSolid(self.cSternSphere) + self.cSternSphereNodePath = self.avatarNodePath.attachNewNode( + cSternSphereNode) + self.cSternSphereBitMask = bitmask + + cSternSphereNode.setFromCollideMask(self.cSphereBitMask) + cSternSphereNode.setIntoCollideMask(BitMask32.allOff()) + + self.pusher.addCollider( + self.cSternSphereNodePath, self.avatarNodePath) + + # hide other things on my ship that these spheres might collide + # with and which I dont need anyways... + shipCollWall = self.avatarNodePath.hull.find("**/collision_hull") + if not shipCollWall.isEmpty(): + shipCollWall.stash() + + def takedownPhysics(self): + assert(self.debugPrint("takedownPhysics()")) + if hasattr(self, "phys"): + for i in self.nodes: + i.removeNode() + del self.phys + if self.ship != None: + self.ship.worldVelocity = Vec3.zero() + + def setupPhysics(self, avatarNodePath): + assert(self.debugPrint("setupPhysics()")) + if avatarNodePath is None: + return + assert not avatarNodePath.isEmpty() + + self.takedownPhysics() + self.nodes = [] + self.phys=PhysicsManager() + + if 0: + # Connect to Physics Manager: + self.actorNode=ActorNode("ship-physicsActor") + self.actorNode.getPhysicsObject().setOriented(1) + self.actorNode.getPhysical(0).setViscosity(0.1) + physicsActor=render.attachNewNode(self.actorNode) + physicsActor.setPos(avatarNodePath, Vec3(0)) + physicsActor.setHpr(avatarNodePath, Vec3(0)) + avatarNodePath.reparentTo(physicsActor) + avatarNodePath.setPos(Vec3(0)) + avatarNodePath.setHpr(Vec3(0)) + avatarNodePath.assign(physicsActor) + else: + physicsActor = avatarNodePath + self.actorNode = physicsActor.node() + self.actorNode.getPhysicsObject().setOriented(1) + self.actorNode.getPhysical(0).setViscosity(0.1) + + fn=ForceNode("ship gravity") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + gravity=LinearVectorForce(0.0, 0.0, self.__gravity) + fn.addForce(gravity) + self.phys.addLinearForce(gravity) + self.gravity = gravity + + if 0: + fn=ForceNode("ship buoyancy") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + buoyancy=LinearVectorForce(0.0, 0.0, 0.0) + fn.addForce(buoyancy) + self.phys.addLinearForce(buoyancy) + self.buoyancy = buoyancy + + if 1: + fn=ForceNode("ship buoyancy bow") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + buoyancy=LinearVectorForce(0.0, 0.0, 0.0) + fn.addForce(buoyancy) + self.phys.addLinearForce(buoyancy) + self.buoyancyBow = buoyancy + + fn=ForceNode("ship buoyancy stern") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + buoyancy=LinearVectorForce(0.0, 0.0, 0.0) + fn.addForce(buoyancy) + self.phys.addLinearForce(buoyancy) + self.buoyancyStern = buoyancy + + fn=ForceNode("ship buoyancy port") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + buoyancy=LinearVectorForce(0.0, 0.0, 0.0) + fn.addForce(buoyancy) + self.phys.addLinearForce(buoyancy) + self.buoyancyPort = buoyancy + + fn=ForceNode("ship buoyancy starboard") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + buoyancy=LinearVectorForce(0.0, 0.0, 0.0) + fn.addForce(buoyancy) + self.phys.addLinearForce(buoyancy) + self.buoyancyStarboard = buoyancy + + fn=ForceNode("ship keel") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + self.keel=AngularVectorForce(0.0, 0.0, 0.0) + fn.addForce(self.keel) + self.phys.addAngularForce(self.keel) + + fn=ForceNode("ship priorParent") + fnp=NodePath(fn) + fnp.reparentTo(render) + self.nodes.append(fnp) + priorParent=LinearVectorForce(0.0, 0.0, 0.0) + fn.addForce(priorParent) + self.phys.addLinearForce(priorParent) + self.priorParentNp = fnp + self.priorParent = priorParent + + if 1: + fn=ForceNode("ship viscosity") + fnp=NodePath(fn) + #fnp.reparentTo(physicsActor) + fnp.reparentTo(render) + self.nodes.append(fnp) + self.avatarViscosity=LinearFrictionForce(0.0, 1.0, 0) + self.avatarViscosity.setCoef(0.5) + self.avatarViscosity.setAmplitude(2) + fn.addForce(self.avatarViscosity) + self.phys.addLinearForce(self.avatarViscosity) + + self.phys.attachLinearIntegrator(LinearEulerIntegrator()) + self.phys.attachAngularIntegrator(AngularEulerIntegrator()) + self.phys.attachPhysicalnode(physicsActor.node()) + + if 0: + self.momentumForce=LinearVectorForce(0.0, 0.0, 0.0) + fn=ForceNode("ship momentum") + fnp=NodePath(fn) + fnp.reparentTo(render) + self.nodes.append(fnp) + fn.addForce(self.momentumForce) + self.phys.addLinearForce(self.momentumForce) + + self.acForce=LinearVectorForce(0.0, 0.0, 0.0) + self.acForce.setAmplitude(5) + fn=ForceNode("ship avatarControls") + fnp=NodePath(fn) + fnp.reparentTo(render) + self.nodes.append(fnp) + fn.addForce(self.acForce) + self.phys.addLinearForce(self.acForce) + #self.phys.removeLinearForce(self.acForce) + #fnp.remove() + + if 0 or self.useHeightRay: + #self.setupRay(self.floorBitmask, self.avatarRadius) + self.setupRay(self.floorBitmask, 0.0) + + + #avatarNodePath.reparentTo(render) + self.avatarNodePath = avatarNodePath + #self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos()) + #self.actorNode.updateTransform() + self.setupSphere(self.wallBitmask|self.floorBitmask, self.avatarRadius) + + + assert not avatarNodePath.isEmpty() + + self.setCollisionsActive(1) + + def setWallBitMask(self, bitMask): + self.wallBitmask = bitMask + + def setFloorBitMask(self, bitMask): + self.floorBitmask = bitMask + + def initializeCollisions(self, collisionTraverser, + avatarRadius = 1.4, floorOffset = 1.0, reach = 1.0, + width = 3.0, length = 5.0, height = 2.5): + """ + width is feet from port to starboard. + length is feet from aft to bow. + height is feet from bildge to deck (i.e. not including mast height). + + Set up the avatar collisions + """ + assert(self.debugPrint("initializeCollisions()")) + self.cTrav = collisionTraverser + self.avatarRadius = avatarRadius + self.floorOffset = floorOffset + self.reach = reach + if self.useBowSternSpheres: + self.frontSphereOffset = frontSphereOffset + self.backSphereOffset = backSphereOffset + self.width = width + self.length = length + self.height = height + + def deleteCollisions(self): + assert(self.debugPrint("deleteCollisions()")) + del self.cTrav + + if self.useHeightRay: + del self.cRayQueue + self.cRayNodePath.removeNode() + del self.cRayNodePath + + if hasattr(self, "cSphere"): + del self.cSphere + self.cSphereNodePath.removeNode() + del self.cSphereNodePath + + del self.pusher + + self.getAirborneHeight = None + + def setTag(self, key, value): + if not hasattr(self, "collisionTags"): + self.collisionTags = {} + self.collisionTags[key] = value + + 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 setCollisionsActive(self, active = 1): + assert(self.debugPrint("collisionsActive(active=%s)"%(active,))) + if self.collisionsActive != active: + self.collisionsActive = active + if active: + if self.useBowSternSpheres: + #self.cTrav.addCollider(self.cSphereNodePath, self.pusher) + self.cTrav.addCollider(self.cBowSphereNodePath, self.pusher) + self.cTrav.addCollider(self.cSternSphereNodePath, self.pusher) + if self.useHeightRay: + if self.useLifter: + self.cTrav.addCollider(self.cRayNodePath, self.lifter) + else: + self.cTrav.addCollider(self.cRayNodePath, self.cRayQueue) + else: + if self.useBowSternSpheres: + #self.cTrav.removeCollider(self.cSphereNodePath) + self.cTrav.removeCollider(self.cBowSphereNodePath) + self.cTrav.removeCollider(self.cSternSphereNodePath) + 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 addBlastForce(self, vector): + pass + + def displayDebugInfo(self): + """ + For debug use. + """ + onScreenDebug.add("w controls", "ShipPilot") + + onScreenDebug.add("w ship", self.ship) + onScreenDebug.add("w isAirborne", self.isAirborne) + onScreenDebug.add("posDelta1", + self.avatarNodePath.getPosDelta(render).pPrintValues()) + + physObject=self.actorNode.getPhysicsObject() + if 0: + onScreenDebug.add("w posDelta3", + render.getRelativeVector( + self.avatarNodePath, + self.avatarNodePath.getPosDelta(render)).pPrintValues()) + if 0: + onScreenDebug.add("w gravity", + self.gravity.getLocalVector().pPrintValues()) + onScreenDebug.add("w priorParent", + self.priorParent.getLocalVector().pPrintValues()) + + onScreenDebug.add("w physObject pos", + physObject.getPosition().pPrintValues()) + onScreenDebug.add("w physObject hpr", + physObject.getOrientation().getHpr().pPrintValues()) + onScreenDebug.add("w physObject orien", + physObject.getOrientation().pPrintValues()) + if 1: + physObject = physObject.getVelocity() + onScreenDebug.add("w physObject vec", + physObject.pPrintValues()) + onScreenDebug.add("w physObject len", + "% 10.4f"%physObject.length()) + + acForce = self.acForce.getLocalVector() + onScreenDebug.add("w acForce vec", + acForce.pPrintValues()) + onScreenDebug.add("w acForce len", + "% 10.4f"%acForce.length()) + + onScreenDebug.add("w avatarViscosity", + "% 10.4f"%(self.avatarViscosity.getCoef(),)) + + #onScreenDebug.add("physMgr", + # self.phys.debugOutput()) + onScreenDebug.add("orientation", + self.actorNode.getPhysicsObject().getOrientation().pPrintValues()) + #print "ship orientation:", self.actorNode.getPhysicsObject().getOrientation().pPrintValues() + + if 0: + momentumForce = self.momentumForce.getLocalVector() + onScreenDebug.add("w momentumForce vec", + momentumForce.pPrintValues()) + onScreenDebug.add("w momentumForce len", + "% 10.4f"%momentumForce.length()) + + if 1: + keel = self.keel.getLocalVector() + onScreenDebug.add("w keel vec", + keel.pPrintValues()) + if 0: + onScreenDebug.add("posDelta4", + self.priorParentNp.getRelativeVector( + render, + self.avatarNodePath.getPosDelta(render)).pPrintValues()) + if 1: + onScreenDebug.add("w priorParent", + self.priorParent.getLocalVector().pPrintValues()) + if 0: + onScreenDebug.add("w priorParent po", + self.priorParent.getVector(physObject).pPrintValues()) + + if 1: + onScreenDebug.add("w contact", + self.actorNode.getContactVector().pPrintValues()) + #onScreenDebug.add("airborneHeight", "% 10.4f"%( + # self.getAirborneHeight(),)) + + def handleAvatarControls(self, task): + """ + Check on the arrow keys and update the avatar. + """ + if __debug__: + if self.wantDebugIndicator: + 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() + + if 0: + depth=physObject.getPosition().getZ() + if depth < 0.0: + # self.buoyancy.setVector(Vec3.zero()) + pass + else: + # self.buoyancy.setVector(Vec3.zero()) + physObject.setPosition(Point3( + physObject.getPosition().getX(), + physObject.getPosition().getY(), + 0.0)) + self.actorNode.updateTransform() + #self.buoyancy.setVector(Vec3(0, 0, -depth)) + elif 0: + physObject.setPosition(Point3( + physObject.getPosition().getX(), + physObject.getPosition().getY(), + physObject.getPosition().getZ())) + self.actorNode.updateTransform() + + # get the button states: + forward = inputState.isSet("forward") + reverse = inputState.isSet("reverse") + turnLeft = inputState.isSet("slideLeft") or inputState.isSet("turnLeft") + turnRight = inputState.isSet("slideRight") or inputState.isSet("turnRight") + slide = inputState.isSet("slide") + slideLeft = 0 + slideRight = 0 + jump = inputState.isSet("jump") + # Determine what the speeds are based on the buttons: + + # this was causing the boat to get stuck moving forward or back + if 0: + if not hasattr(self, "sailsDeployed"): + self.sailsDeployed = 0.0 + if forward and reverse: + # Way anchor: + self.__speed = 0.0 + physObject.setVelocity(Vec3.zero()) + elif forward: + self.sailsDeployed += 0.25 + if self.sailsDeployed > 1.0: + self.sailsDeployed = 1.0 + elif reverse: + self.sailsDeployed -= 0.25 + if self.sailsDeployed < -1.0: + self.sailsDeployed = -1.0 + self.__speed = self.ship.acceleration * self.sailsDeployed + else: + self.__speed=(forward and self.ship.acceleration or + reverse and -self.ship.reverseAcceleration) + avatarSlideSpeed=self.ship.acceleration*0.5 + #self.__slideSpeed=slide and ( + # (turnLeft and -avatarSlideSpeed) or + # (turnRight and avatarSlideSpeed)) + self.__slideSpeed=(forward or reverse) and ( + (slideLeft and -avatarSlideSpeed) or + (slideRight and avatarSlideSpeed)) + self.__rotationSpeed=not slide and ( + (turnLeft and self.ship.turnRate) or + (turnRight and -self.ship.turnRate)) + + + # Enable debug turbo mode + maxSpeed = self.ship.maxSpeed + if __debug__: + debugRunning = inputState.isSet("debugRunning") + if debugRunning or base.localAvatar.getTurbo(): + self.__speed*=4.0 + self.__slideSpeed*=4.0 + self.__rotationSpeed*=1.25 + maxSpeed = self.ship.maxSpeed * 4.0 + + + #*# + if not hasattr(self, "currentTurning"): + self.currentTurning = 0.0 + self.currentTurning += self.__rotationSpeed + if self.currentTurning > self.ship.maxTurn: + self.currentTurning = self.ship.maxTurn + elif self.currentTurning < -self.ship.maxTurn: + self.currentTurning = -self.ship.maxTurn + if turnLeft or turnRight: + mult = .9 + elif forward or reverse: + mult = .82 + else: + mult = .8 + self.currentTurning *= mult + if self.currentTurning < 0.001 and self.currentTurning > -0.001: + self.currentTurning = 0.0 + self.__rotationSpeed = self.currentTurning + + + if self.wantDebugIndicator: + self.displayDebugInfo() + + # How far did we move based on the amount of time elapsed? + dt=ClockObject.getGlobalClock().getDt() + + if self.needToDeltaPos: + self.setPriorParentVector() + self.needToDeltaPos = 0 + + 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: + messenger.send("jumpHardLand") + else: + messenger.send("jumpLand") + self.priorParent.setVector(Vec3.zero()) + self.isAirborne = 0 + elif 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 + + #debugTempH=self.avatarNodePath.getH() + if __debug__: + q1=self.avatarNodePath.getQuat() + q2=physObject.getOrientation() + q1.normalize() + q2.normalize() + assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr() + assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001) + + 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") + + #debugTempH=self.avatarNodePath.getH() + if __debug__: + q1=self.avatarNodePath.getQuat() + q2=physObject.getOrientation() + q1.normalize() + q2.normalize() + assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr() + assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001) + + # Check to see if we're moving at all: + physVel = physObject.getVelocity() + physVelLen = physVel.length() + if (physVelLen!=0. + or self.__speed + or self.__slideSpeed + or self.__rotationSpeed + or moveToGround!=Vec3.zero()): + distance = dt * self.__speed + goForward = True + if (distance < 0): + goForward = False + distance /= 5 + slideDistance = dt * self.__slideSpeed + rotation = dt * self.__rotationSpeed + + # 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) + + #newVector = self.acForce.getLocalVector()+Vec3(step) + newVector = Vec3(step) + #newVector=Vec3(rotMat.xform(newVector)) + #maxLen = maxSpeed + if (goForward): + maxLen = self.ship.acceleration + else: + maxLen = self.ship.reverseAcceleration + if newVector.length() > maxLen: + newVector.normalize() + newVector *= maxLen + + + newVector.normalize() + newVector *= maxLen + if __debug__: + onScreenDebug.add("newVector", + newVector) + onScreenDebug.add("newVector length", + newVector.length()) + self.acForce.setVector(Vec3(newVector)) + + + #momentum = self.momentumForce.getLocalVector() + #momentum *= 0.9 + #self.momentumForce.setVector(momentum) + + + #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.getH()==debugTempH-rotation + messenger.send("avatarMoving") + else: + # even if there are no active inputs, we still might be moving + assert physObject.getVelocity().length() == 0. + self.__vel.set(0.0, 0.0, 0.0) + goForward = True + + + #*# + speed = physVel + if (goForward): + if physVelLen > maxSpeed: + speed.normalize() + speed *= maxSpeed + else: + if physVelLen > self.ship.maxReverseSpeed: + speed.normalize() + speed *= self.ship.maxReverseSpeed + + #speed *= 1.0 - dt * 0.05 + + # modify based on sail damage + speed *= self.ship.Sp + speed /= self.ship.maxSp + physObject.setVelocity(speed) + + #rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up()) + #speed=rotMat.xform(speed) + # The momentumForce makes it feel like we are sliding on ice -- Joe + # f = Vec3(self.__vel) + # f.normalize() + # self.momentumForce.setVector(Vec3(f*(speed.length()*0.9))) + + + if __debug__: + q1=self.avatarNodePath.getQuat() + q2=physObject.getOrientation() + q1.normalize() + q2.normalize() + assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr() + assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001) + + # Clear the contact vector so we can + # tell if we contact something next frame + self.actorNode.setContactVector(Vec3.zero()) + + self.__oldPosDelta = self.avatarNodePath.getPosDelta(render) + self.__oldDt = dt + assert hasattr(self.ship, 'worldVelocity') + self.ship.worldVelocity = self.__oldPosDelta*(1/self.__oldDt) + if self.wantDebugIndicator: + onScreenDebug.add("w __oldPosDelta vec", + self.__oldPosDelta.pPrintValues()) + onScreenDebug.add("w __oldPosDelta len", + "% 10.4f"%self.__oldPosDelta.length()) + onScreenDebug.add("w __oldDt", + "% 10.4f"%self.__oldDt) + onScreenDebug.add("w worldVelocity vec", + self.ship.worldVelocity.pPrintValues()) + onScreenDebug.add("w worldVelocity len", + "% 10.4f"%self.ship.worldVelocity.length()) + + # if hasattr(self.ship, 'sailBillow'): + # self.ship.sailBillow = self.sailsDeployed + + if hasattr(self.ship, 'currentTurning'): + self.ship.currentTurning = self.currentTurning + + 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.wantDebugIndicator: + 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 getVelocity(self): + return self.__vel + + 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.wantDebugIndicator: + 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)