ShipPilot.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. """
  2. ShipPilot.py is for avatars pilotting ships (or more accurately, a ship as the avatar).
  3. A control such as this one provides:
  4. - creation of the collision nodes
  5. - handling the keyboard and mouse input for avatar movement
  6. - moving the avatar
  7. it does not:
  8. - play sounds
  9. - play animations
  10. although it does send messeges that allow a listener to play sounds or
  11. animations based on control events.
  12. """
  13. from direct.showbase.ShowBaseGlobal import *
  14. from direct.directnotify import DirectNotifyGlobal
  15. from pandac import PhysicsManager
  16. import math
  17. import PhysicsWalker
  18. #import LineStream
  19. class ShipPilot(PhysicsWalker.PhysicsWalker):
  20. notify = DirectNotifyGlobal.directNotify.newCategory("PhysicsWalker")
  21. wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator', 0)
  22. useLifter = 0
  23. useHeightRay = 0
  24. # special methods
  25. def __init__(self, gravity = -32.1740, standableGround=0.707,
  26. hardLandingForce=16.0):
  27. assert(self.debugPrint("PhysicsWalker(gravity=%s, standableGround=%s)"%(
  28. gravity, standableGround)))
  29. PhysicsWalker.PhysicsWalker.__init__(self, gravity = -32.1740, standableGround=0.707,
  30. hardLandingForce=16.0)
  31. self.__gravity=gravity
  32. self.__standableGround=standableGround
  33. self.__hardLandingForce=hardLandingForce
  34. self.needToDeltaPos = 0
  35. self.physVelocityIndicator=None
  36. self.avatarControlForwardSpeed=0
  37. self.avatarControlJumpForce=0
  38. self.avatarControlReverseSpeed=0
  39. self.avatarControlRotateSpeed=0
  40. self.__oldAirborneHeight=None
  41. self.getAirborneHeight=None
  42. self.__oldContact=None
  43. self.__oldPosDelta=Vec3(0)
  44. self.__oldDt=0
  45. self.__speed=0.0
  46. self.__rotationSpeed=0.0
  47. self.__slideSpeed=0.0
  48. self.__vel=Vec3(0.0)
  49. self.collisionsActive = 0
  50. self.isAirborne = 0
  51. self.highMark = 0
  52. def setWalkSpeed(self, forward, jump, reverse, rotate):
  53. assert(self.debugPrint("setWalkSpeed()"))
  54. self.avatarControlForwardSpeed=forward
  55. self.avatarControlJumpForce=0.0
  56. self.avatarControlReverseSpeed=reverse
  57. self.avatarControlRotateSpeed=rotate
  58. def getSpeeds(self):
  59. #assert(self.debugPrint("getSpeeds()"))
  60. return (self.__speed, self.__rotationSpeed)
  61. def setAvatar(self, ship):
  62. self.ship = ship
  63. if ship is None:
  64. self.takedownPhysics()
  65. else:
  66. #self.setupShip()
  67. self.setupPhysics(ship)
  68. #*# Debug:
  69. if not hasattr(ship, "acceleration"):
  70. self.ship.acceleration = 60
  71. self.ship.maxSpeed = 12
  72. self.ship.reverseAcceleration = 10
  73. self.ship.maxReverseSpeed = 20
  74. self.ship.turnRate = 3
  75. self.ship.maxTurn = 30
  76. self.ship.anchorDrag = .9
  77. self.ship.hullDrag = .9
  78. def setupRay(self, floorBitmask, floorOffset):
  79. # This is a ray cast from your head down to detect floor polygons
  80. # A toon is about 4.0 feet high, so start it there
  81. self.cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
  82. cRayNode = CollisionNode('PW.cRayNode')
  83. cRayNode.addSolid(self.cRay)
  84. self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
  85. self.cRayBitMask = floorBitmask
  86. cRayNode.setFromCollideMask(self.cRayBitMask)
  87. cRayNode.setIntoCollideMask(BitMask32.allOff())
  88. if 0 or self.useLifter:
  89. # set up floor collision mechanism
  90. self.lifter = CollisionHandlerFloor()
  91. self.lifter.setInPattern("enter%in")
  92. self.lifter.setOutPattern("exit%in")
  93. self.lifter.setOffset(floorOffset)
  94. # Limit our rate-of-fall with the lifter.
  95. # If this is too low, we actually "fall" off steep stairs
  96. # and float above them as we go down. I increased this
  97. # from 8.0 to 16.0 to prevent this
  98. #self.lifter.setMaxVelocity(16.0)
  99. #self.bobNodePath = self.avatarNodePath.attachNewNode("bob")
  100. #self.lifter.addCollider(self.cRayNodePath, self.cRayNodePath)
  101. self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
  102. else: # useCollisionHandlerQueue
  103. self.cRayQueue = CollisionHandlerQueue()
  104. self.cTrav.addCollider(self.cRayNodePath, self.cRayQueue)
  105. def determineHeight(self):
  106. """
  107. returns the height of the avatar above the ground.
  108. If there is no floor below the avatar, 0.0 is returned.
  109. aka get airborne height.
  110. """
  111. if self.useLifter:
  112. height = self.avatarNodePath.getPos(self.cRayNodePath)
  113. # If the shadow where not pointed strait down, we would need to
  114. # get magnitude of the vector. Since it is strait down, we'll
  115. # just get the z:
  116. #spammy --> assert self.debugPrint("getAirborneHeight() returning %s"%(height.getZ(),))
  117. assert onScreenDebug.add("height", height.getZ())
  118. return height.getZ() - self.floorOffset
  119. else: # useCollisionHandlerQueue
  120. """
  121. returns the height of the avatar above the ground.
  122. If there is no floor below the avatar, 0.0 is returned.
  123. aka get airborne height.
  124. """
  125. height = 0.0
  126. #*#self.cRayTrav.traverse(render)
  127. if self.cRayQueue.getNumEntries() != 0:
  128. # ...we have a floor.
  129. # Choose the highest of the possibly several floors we're over:
  130. self.cRayQueue.sortEntries()
  131. floorPoint = self.cRayQueue.getEntry(0).getFromIntersectionPoint()
  132. height = -floorPoint.getZ()
  133. self.cRayQueue.clearEntries()
  134. if __debug__:
  135. onScreenDebug.add("height", height)
  136. return height
  137. def setupSphere(self, bitmask, avatarRadius):
  138. """
  139. Set up the collision sphere
  140. """
  141. # This is a sphere on the ground to detect barrier collisions
  142. if 0:
  143. self.avatarRadius = avatarRadius
  144. self.cSphere = CollisionTube(Point3(0.0, 0.0, 0.0), Point3(0.0, 40.0, 0.0), avatarRadius)
  145. cSphereNode = CollisionNode('SP.cSphereNode')
  146. cSphereNode.addSolid(self.cSphere)
  147. self.cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
  148. self.cSphereBitMask = bitmask
  149. else:
  150. self.avatarRadius = avatarRadius
  151. self.cSphere = CollisionSphere(0.0, -5.0, 0.0, avatarRadius)
  152. cSphereNode = CollisionNode('SP.cSphereNode')
  153. cSphereNode.addSolid(self.cSphere)
  154. self.cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
  155. self.cSphereBitMask = bitmask
  156. cSphereNode.setFromCollideMask(self.cSphereBitMask)
  157. cSphereNode.setIntoCollideMask(BitMask32.allOff())
  158. # set up collision mechanism
  159. self.pusher = PhysicsCollisionHandler()
  160. self.pusher.setInPattern("enter%in")
  161. self.pusher.setOutPattern("exit%in")
  162. self.pusher.addCollider(self.cSphereNodePath, self.avatarNodePath)
  163. if 1:
  164. self.cBowSphere = CollisionSphere(0.0, 20.0, 0.0, avatarRadius)
  165. cBowSphereNode = CollisionNode('SP.cBowSphereNode')
  166. cBowSphereNode.addSolid(self.cBowSphere)
  167. self.cBowSphereNodePath = self.avatarNodePath.attachNewNode(cBowSphereNode)
  168. self.cBowSphereBitMask = bitmask
  169. cBowSphereNode.setFromCollideMask(self.cSphereBitMask)
  170. cBowSphereNode.setIntoCollideMask(BitMask32.allOff())
  171. self.pusher.addCollider(self.cBowSphereNodePath, self.avatarNodePath)
  172. def takedownPhysics(self):
  173. assert(self.debugPrint("takedownPhysics()"))
  174. if hasattr(self, "phys"):
  175. del self.phys
  176. for i in self.nodes:
  177. i.removeNode()
  178. def setupPhysics(self, avatarNodePath):
  179. assert(self.debugPrint("setupPhysics()"))
  180. if avatarNodePath is None:
  181. return
  182. assert not avatarNodePath.isEmpty()
  183. self.takedownPhysics()
  184. self.nodes = []
  185. self.phys=PhysicsManager.PhysicsManager()
  186. if 0:
  187. # Connect to Physics Manager:
  188. self.actorNode=ActorNode("ship-physicsActor")
  189. self.actorNode.getPhysicsObject().setOriented(1)
  190. self.actorNode.getPhysical(0).setViscosity(0.1)
  191. physicsActor=render.attachNewNode(self.actorNode)
  192. physicsActor.setPos(avatarNodePath, Vec3(0))
  193. physicsActor.setHpr(avatarNodePath, Vec3(0))
  194. avatarNodePath.reparentTo(physicsActor)
  195. avatarNodePath.setPos(Vec3(0))
  196. avatarNodePath.setHpr(Vec3(0))
  197. avatarNodePath.assign(physicsActor)
  198. else:
  199. print "doing getPhysicsObject"
  200. physicsActor = avatarNodePath
  201. self.actorNode = physicsActor.node()
  202. self.actorNode.getPhysicsObject().setOriented(1)
  203. self.actorNode.getPhysical(0).setViscosity(0.1)
  204. fn=ForceNode("ship gravity")
  205. fnp=NodePath(fn)
  206. #fnp.reparentTo(physicsActor)
  207. fnp.reparentTo(render)
  208. self.nodes.append(fnp)
  209. gravity=LinearVectorForce(0.0, 0.0, self.__gravity)
  210. fn.addForce(gravity)
  211. self.phys.addLinearForce(gravity)
  212. self.gravity = gravity
  213. fn=ForceNode("ship buoyancy")
  214. fnp=NodePath(fn)
  215. #fnp.reparentTo(physicsActor)
  216. fnp.reparentTo(render)
  217. self.nodes.append(fnp)
  218. buoyancy=LinearVectorForce(0.0, 0.0, 0.0)
  219. fn.addForce(buoyancy)
  220. self.phys.addLinearForce(buoyancy)
  221. self.buoyancy = buoyancy
  222. fn=ForceNode("ship keel")
  223. fnp=NodePath(fn)
  224. #fnp.reparentTo(physicsActor)
  225. fnp.reparentTo(render)
  226. self.nodes.append(fnp)
  227. self.keel=AngularVectorForce(0.0, 0.0, 0.0)
  228. fn.addForce(self.keel)
  229. self.phys.addAngularForce(self.keel)
  230. fn=ForceNode("ship priorParent")
  231. fnp=NodePath(fn)
  232. fnp.reparentTo(render)
  233. self.nodes.append(fnp)
  234. priorParent=LinearVectorForce(0.0, 0.0, 0.0)
  235. fn.addForce(priorParent)
  236. self.phys.addLinearForce(priorParent)
  237. self.priorParentNp = fnp
  238. self.priorParent = priorParent
  239. if 1:
  240. fn=ForceNode("ship viscosity")
  241. fnp=NodePath(fn)
  242. #fnp.reparentTo(physicsActor)
  243. fnp.reparentTo(render)
  244. self.nodes.append(fnp)
  245. self.avatarViscosity=LinearFrictionForce(0.0, 1.0, 0)
  246. #self.avatarViscosity.setCoef(0.9)
  247. fn.addForce(self.avatarViscosity)
  248. self.phys.addLinearForce(self.avatarViscosity)
  249. self.phys.attachLinearIntegrator(LinearEulerIntegrator())
  250. self.phys.attachAngularIntegrator(AngularEulerIntegrator())
  251. self.phys.attachPhysicalnode(physicsActor.node())
  252. self.momentumForce=LinearVectorForce(0.0, 0.0, 0.0)
  253. fn=ForceNode("ship momentum")
  254. fnp=NodePath(fn)
  255. fnp.reparentTo(render)
  256. self.nodes.append(fnp)
  257. fn.addForce(self.momentumForce)
  258. self.phys.addLinearForce(self.momentumForce)
  259. self.acForce=LinearVectorForce(0.0, 0.0, 0.0)
  260. fn=ForceNode("ship avatarControls")
  261. fnp=NodePath(fn)
  262. fnp.reparentTo(render)
  263. self.nodes.append(fnp)
  264. fn.addForce(self.acForce)
  265. self.phys.addLinearForce(self.acForce)
  266. #self.phys.removeLinearForce(self.acForce)
  267. #fnp.remove()
  268. if 0 or self.useHeightRay:
  269. #self.setupRay(self.floorBitmask, self.avatarRadius)
  270. self.setupRay(self.floorBitmask, 0.0)
  271. #avatarNodePath.reparentTo(render)
  272. self.avatarNodePath = avatarNodePath
  273. #self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos())
  274. #self.actorNode.updateTransform()
  275. self.setupSphere(self.wallBitmask|self.floorBitmask, self.avatarRadius)
  276. assert not avatarNodePath.isEmpty()
  277. self.setCollisionsActive(1)
  278. def initializeCollisions(self, collisionTraverser,
  279. wallBitmask, floorBitmask,
  280. avatarRadius = 1.4, floorOffset = 1.0, reach = 1.0):
  281. """
  282. Set up the avatar collisions
  283. """
  284. assert(self.debugPrint("initializeCollisions()"))
  285. self.cTrav = collisionTraverser
  286. self.floorOffset = floorOffset = 7.0
  287. self.wallBitmask = wallBitmask
  288. self.floorBitmask = floorBitmask
  289. self.avatarRadius = avatarRadius
  290. self.floorOffset = floorOffset
  291. self.reach = reach
  292. def setAirborneHeightFunc(self, getAirborneHeight):
  293. self.getAirborneHeight = getAirborneHeight
  294. def setAvatarPhysicsIndicator(self, indicator):
  295. """
  296. indicator is a NodePath
  297. """
  298. assert(self.debugPrint("setAvatarPhysicsIndicator()"))
  299. self.cSphereNodePath.show()
  300. if indicator:
  301. # Indicator Node:
  302. change=render.attachNewNode("change")
  303. #change.setPos(Vec3(1.0, 1.0, 1.0))
  304. #change.setHpr(0.0, 0.0, 0.0)
  305. change.setScale(0.1)
  306. #change.setColor(Vec4(1.0, 1.0, 1.0, 1.0))
  307. indicator.reparentTo(change)
  308. indicatorNode=render.attachNewNode("physVelocityIndicator")
  309. #indicatorNode.setScale(0.1)
  310. #indicatorNode.setP(90.0)
  311. indicatorNode.setPos(self.avatarNodePath, 0.0, 0.0, 6.0)
  312. indicatorNode.setColor(0.0, 0.0, 1.0, 1.0)
  313. change.reparentTo(indicatorNode)
  314. self.physVelocityIndicator=indicatorNode
  315. # Contact Node:
  316. contactIndicatorNode=render.attachNewNode("physContactIndicator")
  317. contactIndicatorNode.setScale(0.25)
  318. contactIndicatorNode.setP(90.0)
  319. contactIndicatorNode.setPos(self.avatarNodePath, 0.0, 0.0, 5.0)
  320. contactIndicatorNode.setColor(1.0, 0.0, 0.0, 1.0)
  321. indicator.instanceTo(contactIndicatorNode)
  322. self.physContactIndicator=contactIndicatorNode
  323. else:
  324. print "failed load of physics indicator"
  325. def avatarPhysicsIndicator(self, task):
  326. #assert(self.debugPrint("avatarPhysicsIndicator()"))
  327. # Velocity:
  328. self.physVelocityIndicator.setPos(self.avatarNodePath, 0.0, 0.0, 6.0)
  329. physObject=self.actorNode.getPhysicsObject()
  330. a=physObject.getVelocity()
  331. self.physVelocityIndicator.setScale(math.sqrt(a.length()))
  332. a+=self.physVelocityIndicator.getPos()
  333. self.physVelocityIndicator.lookAt(Point3(a))
  334. # Contact:
  335. contact=self.actorNode.getContactVector()
  336. if contact==Vec3.zero():
  337. self.physContactIndicator.hide()
  338. else:
  339. self.physContactIndicator.show()
  340. self.physContactIndicator.setPos(self.avatarNodePath, 0.0, 0.0, 5.0)
  341. #contact=self.actorNode.getContactVector()
  342. point=Point3(contact+self.physContactIndicator.getPos())
  343. self.physContactIndicator.lookAt(point)
  344. return Task.cont
  345. def deleteCollisions(self):
  346. assert(self.debugPrint("deleteCollisions()"))
  347. del self.cTrav
  348. if self.useHeightRay:
  349. del self.cRayQueue
  350. self.cRayNodePath.removeNode()
  351. del self.cRayNodePath
  352. del self.cSphere
  353. self.cSphereNodePath.removeNode()
  354. del self.cSphereNodePath
  355. del self.pusher
  356. del self.getAirborneHeight
  357. def setCollisionsActive(self, active = 1):
  358. assert(self.debugPrint("collisionsActive(active=%s)"%(active,)))
  359. if self.collisionsActive != active:
  360. self.collisionsActive = active
  361. if active:
  362. self.cTrav.addCollider(self.cSphereNodePath, self.pusher)
  363. self.cTrav.addCollider(self.cBowSphereNodePath, self.pusher)
  364. if self.useHeightRay:
  365. if self.useLifter:
  366. self.cTrav.addCollider(self.cRayNodePath, self.lifter)
  367. else:
  368. self.cTrav.addCollider(self.cRayNodePath, self.cRayQueue)
  369. else:
  370. self.cTrav.removeCollider(self.cSphereNodePath)
  371. self.cTrav.removeCollider(self.cBowSphereNodePath)
  372. if self.useHeightRay:
  373. self.cTrav.removeCollider(self.cRayNodePath)
  374. # Now that we have disabled collisions, make one more pass
  375. # right now to ensure we aren't standing in a wall.
  376. self.oneTimeCollide()
  377. def getCollisionsActive(self):
  378. assert(self.debugPrint("getCollisionsActive() returning=%s"%(
  379. self.collisionsActive,)))
  380. return self.collisionsActive
  381. def placeOnFloor(self):
  382. """
  383. Make a reasonable effort to place the avatar on the ground.
  384. For example, this is useful when switching away from the
  385. current walker.
  386. """
  387. self.oneTimeCollide()
  388. self.avatarNodePath.setZ(self.avatarNodePath.getZ()-self.getAirborneHeight())
  389. def oneTimeCollide(self):
  390. """
  391. Makes one quick collision pass for the avatar, for instance as
  392. a one-time straighten-things-up operation after collisions
  393. have been disabled.
  394. """
  395. assert(self.debugPrint("oneTimeCollide()"))
  396. tempCTrav = CollisionTraverser("oneTimeCollide")
  397. if self.useHeightRay:
  398. if self.useLifter:
  399. tempCTrav.addCollider(self.cRayNodePath, self.lifter)
  400. else:
  401. tempCTrav.addCollider(self.cRayNodePath, self.cRayQueue)
  402. tempCTrav.traverse(render)
  403. def displayDebugInfo(self):
  404. """
  405. For debug use.
  406. """
  407. onScreenDebug.add("w controls", "ShipPilot")
  408. onScreenDebug.add("w ship", self.ship)
  409. onScreenDebug.add("w isAirborne", self.isAirborne)
  410. onScreenDebug.add("posDelta1",
  411. self.avatarNodePath.getPosDelta(render).pPrintValues())
  412. physObject=self.actorNode.getPhysicsObject()
  413. if 0:
  414. onScreenDebug.add("w posDelta3",
  415. render.getRelativeVector(
  416. self.avatarNodePath,
  417. self.avatarNodePath.getPosDelta(render)).pPrintValues())
  418. if 0:
  419. onScreenDebug.add("w gravity",
  420. self.gravity.getLocalVector().pPrintValues())
  421. onScreenDebug.add("w priorParent",
  422. self.priorParent.getLocalVector().pPrintValues())
  423. onScreenDebug.add("w physObject pos",
  424. physObject.getPosition().pPrintValues())
  425. onScreenDebug.add("w physObject hpr",
  426. physObject.getOrientation().getHpr().pPrintValues())
  427. onScreenDebug.add("w physObject orien",
  428. physObject.getOrientation().pPrintValues())
  429. if 1:
  430. physObject = physObject.getVelocity()
  431. onScreenDebug.add("w physObject vec",
  432. physObject.pPrintValues())
  433. onScreenDebug.add("w physObject len",
  434. "% 10.4f"%physObject.length())
  435. acForce = self.acForce.getLocalVector()
  436. onScreenDebug.add("w acForce vec",
  437. acForce.pPrintValues())
  438. onScreenDebug.add("w acForce len",
  439. "% 10.4f"%acForce.length())
  440. onScreenDebug.add("w avatarViscosity",
  441. "% 10.4f"%(self.avatarViscosity.getCoef(),))
  442. #onScreenDebug.add("physMgr",
  443. # self.phys.debugOutput())
  444. onScreenDebug.add("orientation",
  445. self.actorNode.getPhysicsObject().getOrientation().pPrintValues())
  446. #print "ship orientation:", self.actorNode.getPhysicsObject().getOrientation().pPrintValues()
  447. momentumForce = self.momentumForce.getLocalVector()
  448. onScreenDebug.add("w momentumForce vec",
  449. momentumForce.pPrintValues())
  450. onScreenDebug.add("w momentumForce len",
  451. "% 10.4f"%momentumForce.length())
  452. keel = self.keel.getLocalVector()
  453. onScreenDebug.add("w keel vec",
  454. keel.pPrintValues())
  455. if 0:
  456. onScreenDebug.add("posDelta4",
  457. self.priorParentNp.getRelativeVector(
  458. render,
  459. self.avatarNodePath.getPosDelta(render)).pPrintValues())
  460. if 1:
  461. onScreenDebug.add("w priorParent",
  462. self.priorParent.getLocalVector().pPrintValues())
  463. if 0:
  464. onScreenDebug.add("w priorParent po",
  465. self.priorParent.getVector(physObject).pPrintValues())
  466. if 1:
  467. onScreenDebug.add("w contact",
  468. self.actorNode.getContactVector().pPrintValues())
  469. #onScreenDebug.add("airborneHeight", "% 10.4f"%(
  470. # self.getAirborneHeight(),))
  471. def handleAvatarControls(self, task):
  472. """
  473. Check on the arrow keys and update the avatar.
  474. """
  475. if __debug__:
  476. if self.wantDebugIndicator:
  477. onScreenDebug.append("localAvatar pos = %s\n"%(base.localAvatar.getPos().pPrintValues(),))
  478. onScreenDebug.append("localAvatar h = % 10.4f\n"%(base.localAvatar.getH(),))
  479. #onScreenDebug.append("localAvatar anim = %s\n"%(base.localAvatar.animFSM.getCurrentState().getName(),))
  480. #assert(self.debugPrint("handleAvatarControls(task=%s)"%(task,)))
  481. physObject=self.actorNode.getPhysicsObject()
  482. #rotAvatarToPhys=Mat3.rotateMatNormaxis(-self.avatarNodePath.getH(), Vec3.up())
  483. #rotPhysToAvatar=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
  484. contact=self.actorNode.getContactVector()
  485. depth=physObject.getPosition().getZ()
  486. if depth < 0.0:
  487. self.buoyancy.setVector(Vec3.zero())
  488. else:
  489. self.buoyancy.setVector(Vec3.zero())
  490. physObject.setPosition(Point3(physObject.getPosition().getX(), physObject.getPosition().getY(), 0.0))
  491. #self.buoyancy.setVector(Vec3(0, 0, -depth))
  492. # get the button states:
  493. forward = inputState.isSet("forward")
  494. reverse = inputState.isSet("reverse")
  495. turnLeft = inputState.isSet("turnLeft")
  496. turnRight = inputState.isSet("turnRight")
  497. slide = 0#inputState.isSet("slide")
  498. slideLeft = 0#inputState.isSet("slideLeft")
  499. slideRight = 0#inputState.isSet("slideRight")
  500. jump = inputState.isSet("jump")
  501. # Determine what the speeds are based on the buttons:
  502. if 0:
  503. if not hasattr(self, "sailsDeployed"):
  504. self.sailsDeployed = 0.0
  505. if forward and reverse:
  506. # Way anchor:
  507. self.__speed = 0.0
  508. physObject.setVelocity(Vec3.zero())
  509. elif forward:
  510. self.sailsDeployed += 0.25
  511. if self.sailsDeployed > 1.0:
  512. self.sailsDeployed = 1.0
  513. elif reverse:
  514. self.sailsDeployed -= 0.25
  515. if self.sailsDeployed < -1.0:
  516. self.sailsDeployed = -1.0
  517. self.__speed = self.ship.acceleration * self.sailsDeployed
  518. else:
  519. self.__speed=(forward and self.ship.acceleration or
  520. reverse and -self.ship.reverseAcceleration)
  521. avatarSlideSpeed=self.ship.acceleration*0.5
  522. #self.__slideSpeed=slide and (
  523. # (turnLeft and -avatarSlideSpeed) or
  524. # (turnRight and avatarSlideSpeed))
  525. self.__slideSpeed=(
  526. (slideLeft and -avatarSlideSpeed) or
  527. (slideRight and avatarSlideSpeed))
  528. self.__rotationSpeed=not slide and (
  529. (turnLeft and self.ship.turnRate) or
  530. (turnRight and -self.ship.turnRate))
  531. if __debug__:
  532. debugRunning = inputState.isSet("debugRunning")
  533. if debugRunning:
  534. self.__speed*=4.0
  535. self.__slideSpeed*=4.0
  536. self.__rotationSpeed*=1.25
  537. #*#
  538. if not hasattr(self, "currentTurning"):
  539. self.currentTurning = 0.0
  540. self.currentTurning += self.__rotationSpeed
  541. if self.currentTurning > self.ship.maxTurn:
  542. self.currentTurning = self.ship.maxTurn
  543. elif self.currentTurning < -self.ship.maxTurn:
  544. self.currentTurning = -self.ship.maxTurn
  545. self.currentTurning *= 0.9
  546. self.__rotationSpeed = self.currentTurning
  547. if self.wantDebugIndicator:
  548. self.displayDebugInfo()
  549. # How far did we move based on the amount of time elapsed?
  550. dt=ClockObject.getGlobalClock().getDt()
  551. if self.needToDeltaPos:
  552. self.setPriorParentVector()
  553. self.needToDeltaPos = 0
  554. airborneHeight=self.getAirborneHeight()
  555. if airborneHeight > self.highMark:
  556. self.highMark = airborneHeight
  557. if __debug__:
  558. onScreenDebug.add("highMark", "% 10.4f"%(self.highMark,))
  559. #if airborneHeight < 0.1: #contact!=Vec3.zero():
  560. if 1:
  561. if (airborneHeight > self.avatarRadius*0.5
  562. or physObject.getVelocity().getZ() > 0.0
  563. ): # Check stair angles before changing this.
  564. # ...the avatar is airborne (maybe a lot or a tiny amount).
  565. self.isAirborne = 1
  566. else:
  567. # ...the avatar is very close to the ground (close enough to be
  568. # considered on the ground).
  569. if self.isAirborne and physObject.getVelocity().getZ() <= 0.0:
  570. # ...the avatar has landed.
  571. contactLength = contact.length()
  572. if contactLength>self.__hardLandingForce:
  573. #print "jumpHardLand"
  574. messenger.send("jumpHardLand")
  575. else:
  576. #print "jumpLand"
  577. messenger.send("jumpLand")
  578. self.priorParent.setVector(Vec3.zero())
  579. self.isAirborne = 0
  580. elif jump:
  581. #print "jump"
  582. #self.__jumpButton=0
  583. messenger.send("jumpStart")
  584. if 0:
  585. # ...jump away from walls and with with the slope normal.
  586. jumpVec=Vec3(contact+Vec3.up())
  587. #jumpVec=Vec3(rotAvatarToPhys.xform(jumpVec))
  588. jumpVec.normalize()
  589. else:
  590. # ...jump straight up, even if next to a wall.
  591. jumpVec=Vec3.up()
  592. jumpVec*=self.avatarControlJumpForce
  593. physObject.addImpulse(Vec3(jumpVec))
  594. self.isAirborne = 1 # Avoid double impulse before fully airborne.
  595. else:
  596. self.isAirborne = 0
  597. if __debug__:
  598. onScreenDebug.add("isAirborne", "%d"%(self.isAirborne,))
  599. else:
  600. if contact!=Vec3.zero():
  601. # ...the avatar has touched something (but might not be on the ground).
  602. contactLength = contact.length()
  603. contact.normalize()
  604. angle=contact.dot(Vec3.up())
  605. if angle>self.__standableGround:
  606. # ...avatar is on standable ground.
  607. if self.__oldContact==Vec3.zero():
  608. #if self.__oldAirborneHeight > 0.1: #self.__oldContact==Vec3.zero():
  609. # ...avatar was airborne.
  610. self.jumpCount-=1
  611. if contactLength>self.__hardLandingForce:
  612. messenger.send("jumpHardLand")
  613. else:
  614. messenger.send("jumpLand")
  615. elif jump:
  616. self.jumpCount+=1
  617. #self.__jumpButton=0
  618. messenger.send("jumpStart")
  619. jump=Vec3(contact+Vec3.up())
  620. #jump=Vec3(rotAvatarToPhys.xform(jump))
  621. jump.normalize()
  622. jump*=self.avatarControlJumpForce
  623. physObject.addImpulse(Vec3(jump))
  624. if contact!=self.__oldContact:
  625. # We must copy the vector to preserve it:
  626. self.__oldContact=Vec3(contact)
  627. self.__oldAirborneHeight=airborneHeight
  628. #debugTempH=self.avatarNodePath.getH()
  629. if __debug__:
  630. q1=self.avatarNodePath.getQuat()
  631. q2=physObject.getOrientation()
  632. q1.normalize()
  633. q2.normalize()
  634. assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr()
  635. assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001)
  636. moveToGround = Vec3.zero()
  637. if not self.useHeightRay or self.isAirborne:
  638. # ...the airborne check is a hack to stop sliding.
  639. self.phys.doPhysics(dt)
  640. if __debug__:
  641. onScreenDebug.add("phys", "on")
  642. else:
  643. physObject.setVelocity(Vec3.zero())
  644. #if airborneHeight>0.001 and contact==Vec3.zero():
  645. # moveToGround = Vec3(0.0, 0.0, -airborneHeight)
  646. #moveToGround = Vec3(0.0, 0.0, -airborneHeight)
  647. moveToGround = Vec3(0.0, 0.0, -self.determineHeight())
  648. if __debug__:
  649. onScreenDebug.add("phys", "off")
  650. #debugTempH=self.avatarNodePath.getH()
  651. if __debug__:
  652. q1=self.avatarNodePath.getQuat()
  653. q2=physObject.getOrientation()
  654. q1.normalize()
  655. q2.normalize()
  656. assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr()
  657. assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001)
  658. # Check to see if we're moving at all:
  659. if 0 or self.__speed or self.__slideSpeed or self.__rotationSpeed or moveToGround!=Vec3.zero():
  660. distance = dt * self.__speed
  661. slideDistance = dt * self.__slideSpeed
  662. rotation = dt * self.__rotationSpeed
  663. # update pos:
  664. # Take a step in the direction of our previous heading.
  665. self.__vel=Vec3(
  666. Vec3.forward() * distance +
  667. Vec3.right() * slideDistance)
  668. # rotMat is the rotation matrix corresponding to
  669. # our previous heading.
  670. rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
  671. step=rotMat.xform(self.__vel)
  672. #newVector = self.acForce.getLocalVector()+Vec3(step)
  673. newVector = Vec3(step)
  674. #newVector=Vec3(rotMat.xform(newVector))
  675. #maxLen = self.ship.maxSpeed
  676. maxLen = self.ship.acceleration
  677. if newVector.length() > maxLen:
  678. newVector.normalize()
  679. newVector *= maxLen
  680. newVector.normalize()
  681. newVector *= maxLen
  682. if __debug__:
  683. onScreenDebug.add("newVector",
  684. newVector)
  685. onScreenDebug.add("newVector length",
  686. newVector.length())
  687. self.acForce.setVector(Vec3(newVector))
  688. #momentum = self.momentumForce.getLocalVector()
  689. #momentum *= 0.9
  690. #self.momentumForce.setVector(momentum)
  691. #physObject.setPosition(Point3(
  692. # physObject.getPosition()+step+moveToGround))
  693. # update hpr:
  694. o=physObject.getOrientation()
  695. r=LRotationf()
  696. r.setHpr(Vec3(rotation, 0.0, 0.0))
  697. physObject.setOrientation(o*r)
  698. # sync the change:
  699. self.actorNode.updateTransform()
  700. #assert self.avatarNodePath.getH()==debugTempH-rotation
  701. messenger.send("avatarMoving")
  702. else:
  703. self.__vel.set(0.0, 0.0, 0.0)
  704. #*#
  705. speed = physObject.getVelocity()
  706. speedLen = speed.length()
  707. if speedLen > self.ship.maxSpeed:
  708. speed.normalize()
  709. speed *= self.ship.maxSpeed
  710. self.avatarViscosity.setCoef(0.5)
  711. #speed *= 1.0 - dt * 0.05
  712. physObject.setVelocity(speed)
  713. #rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
  714. #speed=rotMat.xform(speed)
  715. # The momentumForce makes it feel like we are sliding on ice -- Joe
  716. # f = Vec3(self.__vel)
  717. # f.normalize()
  718. # self.momentumForce.setVector(Vec3(f*(speed.length()*0.9)))
  719. if __debug__:
  720. q1=self.avatarNodePath.getQuat()
  721. q2=physObject.getOrientation()
  722. q1.normalize()
  723. q2.normalize()
  724. assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr()
  725. assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001)
  726. # Clear the contact vector so we can tell if we contact something next frame:
  727. self.actorNode.setContactVector(Vec3.zero())
  728. self.__oldPosDelta = self.avatarNodePath.getPosDelta(render)
  729. self.__oldDt = dt
  730. assert hasattr(self.ship, 'worldVelocity')
  731. self.ship.worldVelocity = self.__oldPosDelta*(1/self.__oldDt)
  732. if self.wantDebugIndicator:
  733. onScreenDebug.add("w __oldPosDelta vec",
  734. self.__oldPosDelta.pPrintValues())
  735. onScreenDebug.add("w __oldPosDelta len",
  736. "% 10.4f"%self.__oldPosDelta.length())
  737. onScreenDebug.add("w __oldDt",
  738. "% 10.4f"%self.__oldDt)
  739. onScreenDebug.add("w worldVelocity vec",
  740. self.ship.worldVelocity.pPrintValues())
  741. onScreenDebug.add("w worldVelocity len",
  742. "% 10.4f"%self.ship.worldVelocity.length())
  743. return Task.cont
  744. def doDeltaPos(self):
  745. assert(self.debugPrint("doDeltaPos()"))
  746. self.needToDeltaPos = 1
  747. def setPriorParentVector(self):
  748. assert(self.debugPrint("doDeltaPos()"))
  749. print "self.__oldDt", self.__oldDt, "self.__oldPosDelta", self.__oldPosDelta
  750. if __debug__:
  751. onScreenDebug.add("__oldDt", "% 10.4f"%self.__oldDt)
  752. onScreenDebug.add("self.__oldPosDelta",
  753. self.__oldPosDelta.pPrintValues())
  754. velocity = self.__oldPosDelta*(1/self.__oldDt)*4.0 # *4.0 is a hack
  755. assert(self.debugPrint(" __oldPosDelta=%s"%(self.__oldPosDelta,)))
  756. assert(self.debugPrint(" velocity=%s"%(velocity,)))
  757. self.priorParent.setVector(Vec3(velocity))
  758. if __debug__:
  759. if self.wantDebugIndicator:
  760. onScreenDebug.add("velocity", velocity.pPrintValues())
  761. def reset(self):
  762. assert(self.debugPrint("reset()"))
  763. self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos())
  764. self.priorParent.setVector(Vec3.zero())
  765. self.highMark = 0
  766. self.actorNode.setContactVector(Vec3.zero())
  767. if __debug__:
  768. contact=self.actorNode.getContactVector()
  769. onScreenDebug.add("priorParent po",
  770. self.priorParent.getVector(self.actorNode.getPhysicsObject()).pPrintValues())
  771. onScreenDebug.add("highMark", "% 10.4f"%(self.highMark,))
  772. onScreenDebug.add("contact", contact.pPrintValues())
  773. def enableAvatarControls(self):
  774. """
  775. Activate the arrow keys, etc.
  776. """
  777. assert(self.debugPrint("enableAvatarControls()"))
  778. assert self.collisionsActive
  779. if __debug__:
  780. #self.accept("control-f3", self.spawnTest) #*#
  781. self.accept("f3", self.reset) # for debugging only.
  782. taskName = "AvatarControls-%s"%(id(self),)
  783. # remove any old
  784. taskMgr.remove(taskName)
  785. # spawn the new task
  786. taskMgr.add(self.handleAvatarControls, taskName, 25)
  787. if self.physVelocityIndicator:
  788. taskMgr.add(self.avatarPhysicsIndicator, "AvatarControlsIndicator%s"%(id(self),), 35)
  789. def disableAvatarControls(self):
  790. """
  791. Ignore the arrow keys, etc.
  792. """
  793. assert(self.debugPrint("disableAvatarControls()"))
  794. taskName = "AvatarControls-%s"%(id(self),)
  795. taskMgr.remove(taskName)
  796. taskName = "AvatarControlsIndicator%s"%(id(self),)
  797. taskMgr.remove(taskName)
  798. if __debug__:
  799. self.ignore("control-f3") #*#
  800. self.ignore("f3")
  801. if __debug__:
  802. def setupAvatarPhysicsIndicator(self):
  803. if self.wantDebugIndicator:
  804. indicator=loader.loadModelCopy('phase_5/models/props/dagger')
  805. #self.walkControls.setAvatarPhysicsIndicator(indicator)
  806. def debugPrint(self, message):
  807. """for debugging"""
  808. return self.notify.debug(
  809. str(id(self))+' '+message)