GravityWalker.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. """
  2. GravityWalker.py is for avatars.
  3. A walker 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 walker events.
  12. """
  13. from direct.showbase.ShowBaseGlobal import *
  14. from direct.directnotify import DirectNotifyGlobal
  15. from direct.showbase import DirectObject
  16. import math
  17. class GravityWalker(DirectObject.DirectObject):
  18. notify = DirectNotifyGlobal.directNotify.newCategory("GravityWalker")
  19. wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator', 0)
  20. wantFloorSphere = base.config.GetBool('want-floor-sphere', 0)
  21. # special methods
  22. def __init__(self, gravity = -32.1740, standableGround=0.707,
  23. hardLandingForce=16.0):
  24. assert self.notify.debugStateCall(self)
  25. DirectObject.DirectObject.__init__(self)
  26. self.__gravity=gravity
  27. self.__standableGround=standableGround
  28. self.__hardLandingForce=hardLandingForce
  29. self.mayJump = 1
  30. self.jumpDelayTask = None
  31. self.controlsTask = None
  32. self.indicatorTask = None
  33. self.falling = 0
  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.getAirborneHeight=None
  41. self.priorParent=Vec3(0)
  42. self.__oldPosDelta=Vec3(0)
  43. self.__oldDt=0
  44. self.moving=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 delete(self):
  53. assert self.notify.debugStateCall(self)
  54. if self.doLaterTask is not None:
  55. self.doLaterTask.remove()
  56. del self.doLaterTask
  57. #DirectObject.DirectObject.delete(self)
  58. """
  59. def spawnTest(self):
  60. assert self.notify.debugStateCall(self)
  61. if not self.wantDebugIndicator:
  62. return
  63. from pandac.PandaModules import *
  64. from direct.interval.IntervalGlobal import *
  65. from toontown.coghq import MovingPlatform
  66. if hasattr(self, "platform"):
  67. # Remove the prior instantiation:
  68. self.moveIval.pause()
  69. del self.moveIval
  70. self.platform.destroy()
  71. del self.platform
  72. self.platform2.destroy()
  73. del self.platform2
  74. model = loader.loadModelCopy('phase_9/models/cogHQ/platform1')
  75. fakeId = id(self)
  76. self.platform = MovingPlatform.MovingPlatform()
  77. self.platform.setupCopyModel(fakeId, model, 'platformcollision')
  78. self.platformRoot = render.attachNewNode("GravityWalker-spawnTest-%s"%fakeId)
  79. self.platformRoot.setPos(base.localAvatar, Vec3(0.0, 0.0, 1.0))
  80. self.platformRoot.setHpr(base.localAvatar, Vec3.zero())
  81. self.platform.reparentTo(self.platformRoot)
  82. self.platform2 = MovingPlatform.MovingPlatform()
  83. self.platform2.setupCopyModel(1+fakeId, model, 'platformcollision')
  84. self.platform2Root = render.attachNewNode("GravityWalker-spawnTest2-%s"%fakeId)
  85. self.platform2Root.setPos(base.localAvatar, Vec3(-16.0, 30.0, 1.0))
  86. self.platform2Root.setHpr(base.localAvatar, Vec3.zero())
  87. self.platform2.reparentTo(self.platform2Root)
  88. duration = 5
  89. self.moveIval = Parallel(
  90. Sequence(
  91. WaitInterval(0.3),
  92. LerpPosInterval(self.platform, duration,
  93. Vec3(0.0, 30.0, 0.0),
  94. name='platformOut%s' % fakeId,
  95. fluid = 1),
  96. WaitInterval(0.3),
  97. LerpPosInterval(self.platform, duration,
  98. Vec3(0.0, 0.0, 0.0),
  99. name='platformBack%s' % fakeId,
  100. fluid = 1),
  101. WaitInterval(0.3),
  102. LerpPosInterval(self.platform, duration,
  103. Vec3(0.0, 0.0, 30.0),
  104. name='platformUp%s' % fakeId,
  105. fluid = 1),
  106. WaitInterval(0.3),
  107. LerpPosInterval(self.platform, duration,
  108. Vec3(0.0, 0.0, 0.0),
  109. name='platformDown%s' % fakeId,
  110. fluid = 1),
  111. ),
  112. Sequence(
  113. WaitInterval(0.3),
  114. LerpPosInterval(self.platform2, duration,
  115. Vec3(0.0, -30.0, 0.0),
  116. name='platform2Out%s' % fakeId,
  117. fluid = 1),
  118. WaitInterval(0.3),
  119. LerpPosInterval(self.platform2, duration,
  120. Vec3(0.0, 30.0, 30.0),
  121. name='platform2Back%s' % fakeId,
  122. fluid = 1),
  123. WaitInterval(0.3),
  124. LerpPosInterval(self.platform2, duration,
  125. Vec3(0.0, -30.0, 0.0),
  126. name='platform2Up%s' % fakeId,
  127. fluid = 1),
  128. WaitInterval(0.3),
  129. LerpPosInterval(self.platform2, duration,
  130. Vec3(0.0, 0.0, 0.0),
  131. name='platformDown%s' % fakeId,
  132. fluid = 1),
  133. ),
  134. name='platformIval%s' % fakeId,
  135. )
  136. self.moveIval.loop()
  137. """
  138. def setWalkSpeed(self, forward, jump, reverse, rotate):
  139. assert self.notify.debugStateCall(self)
  140. self.avatarControlForwardSpeed=forward
  141. self.avatarControlJumpForce=jump
  142. self.avatarControlReverseSpeed=reverse
  143. self.avatarControlRotateSpeed=rotate
  144. def getSpeeds(self):
  145. #assert(self.debugPrint("getSpeeds()"))
  146. return (self.speed, self.rotationSpeed, self.slideSpeed)
  147. def setAvatar(self, avatar):
  148. self.avatar = avatar
  149. if avatar is not None:
  150. pass # setup the avatar
  151. def setupRay(self, bitmask, floorOffset, reach):
  152. assert self.notify.debugStateCall(self)
  153. # This is a ray cast from your head down to detect floor polygons.
  154. # This ray start is arbitrarily high in the air. Feel free to use
  155. # a higher or lower value depending on whether you want an avatar
  156. # that is outside of the world to step up to the floor when they
  157. # get under valid floor:
  158. cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
  159. cRayNode = CollisionNode('GW.cRayNode')
  160. cRayNode.addSolid(cRay)
  161. self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
  162. cRayNode.setFromCollideMask(bitmask)
  163. cRayNode.setIntoCollideMask(BitMask32.allOff())
  164. # set up floor collision mechanism
  165. self.lifter = CollisionHandlerGravity()
  166. self.lifter.setGravity(32.174 * 2.0)
  167. self.lifter.addInPattern("enter%in")
  168. self.lifter.addOutPattern("exit%in")
  169. self.lifter.setOffset(floorOffset)
  170. self.lifter.setReach(reach)
  171. # Limit our rate-of-fall with the lifter.
  172. # If this is too low, we actually "fall" off steep stairs
  173. # and float above them as we go down. I increased this
  174. # from 8.0 to 16.0 to prevent this
  175. #self.lifter.setMaxVelocity(16.0)
  176. self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
  177. def setupWallSphere(self, bitmask, avatarRadius):
  178. """
  179. Set up the collision sphere
  180. """
  181. assert self.notify.debugStateCall(self)
  182. # This is a sphere on the ground to detect collisions with
  183. # walls, but not the floor.
  184. self.avatarRadius = avatarRadius
  185. cSphere = CollisionSphere(0.0, 0.0, avatarRadius, avatarRadius)
  186. cSphereNode = CollisionNode('GW.cWallSphereNode')
  187. cSphereNode.addSolid(cSphere)
  188. cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
  189. cSphereNode.setFromCollideMask(bitmask)
  190. cSphereNode.setIntoCollideMask(BitMask32.allOff())
  191. # set up collision mechanism
  192. handler = CollisionHandlerPusher()
  193. #handler.setInPattern("pusher_enter%in")
  194. #handler.setOutPattern("pusher_exit%in")
  195. handler.addCollider(cSphereNodePath, self.avatarNodePath)
  196. self.pusher = handler
  197. self.cWallSphereNodePath = cSphereNodePath
  198. def setupEventSphere(self, bitmask, avatarRadius):
  199. """
  200. Set up the collision sphere
  201. """
  202. assert self.notify.debugStateCall(self)
  203. # This is a sphere a little larger than the wall sphere to
  204. # trigger events.
  205. self.avatarRadius = avatarRadius
  206. cSphere = CollisionSphere(0.0, 0.0, avatarRadius-0.1, avatarRadius*1.04)
  207. # Mark it intangible just to emphasize its non-physical purpose.
  208. cSphere.setTangible(0)
  209. cSphereNode = CollisionNode('GW.cEventSphereNode')
  210. cSphereNode.addSolid(cSphere)
  211. cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
  212. cSphereNode.setFromCollideMask(bitmask)
  213. cSphereNode.setIntoCollideMask(BitMask32.allOff())
  214. # set up collision mechanism
  215. handler = CollisionHandlerEvent()
  216. handler.addInPattern("enter%in")
  217. handler.addOutPattern("exit%in")
  218. self.event = handler
  219. self.cEventSphereNodePath = cSphereNodePath
  220. def setupFloorSphere(self, bitmask, avatarRadius):
  221. """
  222. Set up the collision sphere
  223. """
  224. assert self.notify.debugStateCall(self)
  225. # This is a tiny sphere concentric with the wallSphere to keep
  226. # us from slipping through floors.
  227. self.avatarRadius = avatarRadius
  228. cSphere = CollisionSphere(0.0, 0.0, avatarRadius, 0.01)
  229. cSphereNode = CollisionNode('GW.cFloorSphereNode')
  230. cSphereNode.addSolid(cSphere)
  231. cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
  232. cSphereNode.setFromCollideMask(bitmask)
  233. cSphereNode.setIntoCollideMask(BitMask32.allOff())
  234. # set up collision mechanism
  235. handler = CollisionHandlerPusher()
  236. #handler.setInPattern("pusherFloor_enter%in")
  237. #handler.setOutPattern("pusherFloor_exit%in")
  238. handler.addCollider(cSphereNodePath, self.avatarNodePath)
  239. self.pusherFloor = handler
  240. self.cFloorSphereNodePath = cSphereNodePath
  241. def setWallBitMask(self, bitMask):
  242. self.wallBitmask = bitMask
  243. def setFloorBitMask(self, bitMask):
  244. self.floorBitmask = bitMask
  245. def initializeCollisions(self, collisionTraverser, avatarNodePath,
  246. avatarRadius = 1.4, floorOffset = 1.0, reach = 1.0):
  247. """
  248. floorOffset is how high the avatar can reach. I.e. if the avatar
  249. walks under a ledge that is <= floorOffset above the ground (a
  250. double floor situation), the avatar will step up on to the
  251. ledge (instantly).
  252. Set up the avatar collisions
  253. """
  254. assert self.notify.debugStateCall(self)
  255. assert not avatarNodePath.isEmpty()
  256. self.avatarNodePath = avatarNodePath
  257. self.cTrav = collisionTraverser
  258. self.setupRay(self.floorBitmask, floorOffset, reach)
  259. self.setupWallSphere(self.wallBitmask, avatarRadius)
  260. self.setupEventSphere(self.wallBitmask, avatarRadius)
  261. if self.wantFloorSphere:
  262. self.setupFloorSphere(self.floorBitmask, avatarRadius)
  263. self.setCollisionsActive(1)
  264. def setTag(self, key, value):
  265. self.cEventSphereNodePath.setTag(key, value)
  266. def setAirborneHeightFunc(self, unused_parameter):
  267. assert self.notify.debugStateCall(self)
  268. self.getAirborneHeight = self.lifter.getAirborneHeight
  269. def getAirborneHeight(self):
  270. assert self.notify.debugStateCall(self)
  271. self.lifter.getAirborneHeight()
  272. def setAvatarPhysicsIndicator(self, indicator):
  273. """
  274. indicator is a NodePath
  275. """
  276. assert self.notify.debugStateCall(self)
  277. self.cWallSphereNodePath.show()
  278. def deleteCollisions(self):
  279. assert self.notify.debugStateCall(self)
  280. del self.cTrav
  281. self.cWallSphereNodePath.removeNode()
  282. del self.cWallSphereNodePath
  283. if self.wantFloorSphere:
  284. self.cFloorSphereNodePath.removeNode()
  285. del self.cFloorSphereNodePath
  286. del self.pusher
  287. # del self.pusherFloor
  288. del self.event
  289. del self.lifter
  290. del self.getAirborneHeight
  291. def setCollisionsActive(self, active = 1):
  292. assert self.notify.debugStateCall(self)
  293. if self.collisionsActive != active:
  294. self.collisionsActive = active
  295. # Each time we change the collision geometry, make one
  296. # more pass to ensure we aren't standing in a wall.
  297. self.oneTimeCollide()
  298. if active:
  299. if 1:
  300. # Please let skyler or drose know if this is causing a problem
  301. # This is a bit of a hack fix:
  302. self.avatarNodePath.setP(0.0)
  303. self.avatarNodePath.setR(0.0)
  304. self.cTrav.addCollider(self.cWallSphereNodePath, self.pusher)
  305. if self.wantFloorSphere:
  306. self.cTrav.addCollider(self.cFloorSphereNodePath, self.pusherFloor)
  307. self.cTrav.addCollider(self.cEventSphereNodePath, self.event)
  308. self.cTrav.addCollider(self.cRayNodePath, self.lifter)
  309. else:
  310. self.cTrav.removeCollider(self.cWallSphereNodePath)
  311. if self.wantFloorSphere:
  312. self.cTrav.removeCollider(self.cFloorSphereNodePath)
  313. self.cTrav.removeCollider(self.cEventSphereNodePath)
  314. self.cTrav.removeCollider(self.cRayNodePath)
  315. def getCollisionsActive(self):
  316. assert(self.debugPrint("getCollisionsActive() returning=%s"%(
  317. self.collisionsActive,)))
  318. return self.collisionsActive
  319. def placeOnFloor(self):
  320. """
  321. Make a reasonable effor to place the avatar on the ground.
  322. For example, this is useful when switching away from the
  323. current walker.
  324. """
  325. assert self.notify.debugStateCall(self)
  326. self.oneTimeCollide()
  327. self.avatarNodePath.setZ(self.avatarNodePath.getZ()-self.lifter.getAirborneHeight())
  328. def oneTimeCollide(self):
  329. """
  330. Makes one quick collision pass for the avatar, for instance as
  331. a one-time straighten-things-up operation after collisions
  332. have been disabled.
  333. """
  334. assert self.notify.debugStateCall(self)
  335. self.isAirborne = 0
  336. self.mayJump = 1
  337. tempCTrav = CollisionTraverser("oneTimeCollide")
  338. tempCTrav.addCollider(self.cWallSphereNodePath, self.pusher)
  339. if self.wantFloorSphere:
  340. tempCTrav.addCollider(self.cFloorSphereNodePath, self.event)
  341. tempCTrav.addCollider(self.cRayNodePath, self.lifter)
  342. tempCTrav.traverse(render)
  343. def setMayJump(self, task):
  344. """
  345. This function's use is internal to this class (maybe I'll add
  346. the __ someday). Anyway, if you want to enable or disable
  347. jumping in a general way see the ControlManager (don't use this).
  348. """
  349. assert self.notify.debugStateCall(self)
  350. self.mayJump = 1
  351. return Task.done
  352. def startJumpDelay(self, delay):
  353. assert self.notify.debugStateCall(self)
  354. if self.jumpDelayTask:
  355. self.jumpDelayTask.remove()
  356. self.mayJump = 0
  357. self.jumpDelayTask=taskMgr.doMethodLater(
  358. delay,
  359. self.setMayJump,
  360. "jumpDelay-%s"%id(self))
  361. def addBlastForce(self, vector):
  362. self.lifter.addVelocity(vector.length())
  363. def displayDebugInfo(self):
  364. """
  365. For debug use.
  366. """
  367. onScreenDebug.add("w controls", "GravityWalker")
  368. onScreenDebug.add("w airborneHeight", self.lifter.getAirborneHeight())
  369. onScreenDebug.add("w falling", self.falling)
  370. onScreenDebug.add("w isOnGround", self.lifter.isOnGround())
  371. #onScreenDebug.add("w gravity", self.lifter.getGravity())
  372. #onScreenDebug.add("w jumpForce", self.avatarControlJumpForce)
  373. onScreenDebug.add("w contact normal", self.lifter.getContactNormal().pPrintValues())
  374. onScreenDebug.add("w mayJump", self.mayJump)
  375. onScreenDebug.add("w impact", self.lifter.getImpactVelocity())
  376. onScreenDebug.add("w velocity", self.lifter.getVelocity())
  377. onScreenDebug.add("w isAirborne", self.isAirborne)
  378. onScreenDebug.add("w hasContact", self.lifter.hasContact())
  379. def handleAvatarControls(self, task):
  380. """
  381. Check on the arrow keys and update the avatar.
  382. """
  383. # get the button states:
  384. run = inputState.isSet("run")
  385. forward = inputState.isSet("forward")
  386. reverse = inputState.isSet("reverse")
  387. turnLeft = inputState.isSet("turnLeft")
  388. turnRight = inputState.isSet("turnRight")
  389. slideLeft = inputState.isSet("slideLeft")
  390. slideRight = inputState.isSet("slideRight")
  391. jump = inputState.isSet("jump")
  392. # Determine what the speeds are based on the buttons:
  393. self.speed=(forward and self.avatarControlForwardSpeed or
  394. reverse and -self.avatarControlReverseSpeed)
  395. # Use reverse speed for strafe - that should be about what you want
  396. self.slideSpeed=(slideLeft and -self.avatarControlReverseSpeed or
  397. slideRight and self.avatarControlReverseSpeed)
  398. self.rotationSpeed=not (slideLeft or slideRight) and (
  399. (turnLeft and self.avatarControlRotateSpeed) or
  400. (turnRight and -self.avatarControlRotateSpeed))
  401. if __debug__:
  402. debugRunning = inputState.isSet("debugRunning")
  403. if debugRunning:
  404. self.speed*=4.0
  405. self.slideSpeed*=4.0
  406. self.rotationSpeed*=1.25
  407. if self.needToDeltaPos:
  408. self.setPriorParentVector()
  409. self.needToDeltaPos = 0
  410. if self.wantDebugIndicator:
  411. self.displayDebugInfo()
  412. if self.lifter.isOnGround():
  413. if self.isAirborne:
  414. self.isAirborne = 0
  415. assert(self.debugPrint("isAirborne 0 due to isOnGround() true"))
  416. impact = self.lifter.getImpactVelocity()
  417. if impact < -30.0:
  418. messenger.send("jumpHardLand")
  419. self.startJumpDelay(0.3)
  420. else:
  421. messenger.send("jumpLand")
  422. if impact < -5.0:
  423. self.startJumpDelay(0.2)
  424. # else, ignore the little potholes.
  425. assert(self.isAirborne == 0)
  426. self.priorParent = Vec3.zero()
  427. if jump and self.mayJump:
  428. # The jump button is down and we're close
  429. # enough to the ground to jump.
  430. self.lifter.addVelocity(self.avatarControlJumpForce)
  431. messenger.send("jumpStart")
  432. self.isAirborne = 1
  433. assert(self.debugPrint("isAirborne 1 due to jump"))
  434. else:
  435. if self.isAirborne == 0:
  436. assert(self.debugPrint("isAirborne 1 due to isOnGround() false"))
  437. self.isAirborne = 1
  438. self.__oldPosDelta = self.avatarNodePath.getPosDelta(render)
  439. # How far did we move based on the amount of time elapsed?
  440. self.__oldDt = ClockObject.getGlobalClock().getDt()
  441. dt=self.__oldDt
  442. # Check to see if we're moving at all:
  443. self.moving = self.speed or self.slideSpeed or self.rotationSpeed or (self.priorParent!=Vec3.zero())
  444. if self.moving:
  445. distance = dt * self.speed
  446. slideDistance = dt * self.slideSpeed
  447. rotation = dt * self.rotationSpeed
  448. # Take a step in the direction of our previous heading.
  449. self.vel=Vec3(Vec3.forward() * distance +
  450. Vec3.right() * slideDistance)
  451. if self.vel != Vec3.zero() or self.priorParent != Vec3.zero():
  452. # rotMat is the rotation matrix corresponding to
  453. # our previous heading.
  454. rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
  455. contact = self.lifter.getContactNormal()
  456. forward = contact.cross(Vec3.right())
  457. forward = Vec3(rotMat.xform(forward))
  458. # Consider commenting out this normalize. If you do so
  459. # then going up and down slops is a touch slower and
  460. # steeper terrain can cut the movement in half. Without
  461. # the normalize the movement is slowed by the cosine of
  462. # the slope (i.e. it is multiplied by the sign as a
  463. # side effect of the cross product above).
  464. forward.normalize()
  465. self.vel=Vec3(forward * distance)
  466. if slideDistance:
  467. right = forward.cross(contact)
  468. right = Vec3(rotMat.xform(Vec3.right()))
  469. # See note above for forward.normalize()
  470. right.normalize()
  471. self.vel=Vec3(self.vel + right * slideDistance)
  472. step=self.vel + (self.priorParent * dt)
  473. self.avatarNodePath.setFluidPos(Point3(
  474. self.avatarNodePath.getPos()+step))
  475. self.avatarNodePath.setH(self.avatarNodePath.getH()+rotation)
  476. else:
  477. self.vel.set(0.0, 0.0, 0.0)
  478. if self.moving or jump:
  479. messenger.send("avatarMoving")
  480. return Task.cont
  481. def doDeltaPos(self):
  482. assert self.notify.debugStateCall(self)
  483. self.needToDeltaPos = 1
  484. def setPriorParentVector(self):
  485. assert self.notify.debugStateCall(self)
  486. if __debug__:
  487. onScreenDebug.add("__oldDt", "% 10.4f"%self.__oldDt)
  488. onScreenDebug.add("self.__oldPosDelta",
  489. self.__oldPosDelta.pPrintValues())
  490. velocity = self.__oldPosDelta*(1.0/self.__oldDt)
  491. self.priorParent = Vec3(velocity)
  492. if __debug__:
  493. if self.wantDebugIndicator:
  494. onScreenDebug.add("priorParent", self.priorParent.pPrintValues())
  495. def reset(self):
  496. assert self.notify.debugStateCall(self)
  497. self.lifter.setVelocity(0.0)
  498. self.priorParent=Vec3.zero()
  499. def getVelocity(self):
  500. return self.vel
  501. def enableAvatarControls(self):
  502. """
  503. Activate the arrow keys, etc.
  504. """
  505. assert self.notify.debugStateCall(self)
  506. assert self.collisionsActive
  507. #*#if __debug__:
  508. #*# self.accept("control-f3", self.spawnTest) #*#
  509. # remove any old
  510. if self.controlsTask:
  511. self.controlsTask.remove()
  512. # spawn the new task
  513. taskName = "AvatarControls-%s"%(id(self),)
  514. self.controlsTask = taskMgr.add(self.handleAvatarControls, taskName, 25)
  515. self.isAirborne = 0
  516. self.mayJump = 1
  517. if self.physVelocityIndicator:
  518. if self.indicatorTask:
  519. self.indicatorTask.remove()
  520. self.indicatorTask = taskMgr.add(
  521. self.avatarPhysicsIndicator,
  522. "AvatarControlsIndicator-%s"%(id(self),), 35)
  523. def disableAvatarControls(self):
  524. """
  525. Ignore the arrow keys, etc.
  526. """
  527. assert self.notify.debugStateCall(self)
  528. if self.controlsTask:
  529. self.controlsTask.remove()
  530. self.controlsTask = None
  531. if self.indicatorTask:
  532. self.indicatorTask.remove()
  533. self.indicatorTask = None
  534. if self.jumpDelayTask:
  535. self.jumpDelayTask.remove()
  536. self.jumpDelayTask = None
  537. if __debug__:
  538. self.ignore("control-f3") #*#
  539. if __debug__:
  540. def debugPrint(self, message):
  541. """for debugging"""
  542. return self.notify.debug(
  543. str(id(self))+' '+message)