You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

662 rivejä
19 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
  5. // (c) 2009-2012 Cédric Lecacheur <jordx@free.fr>
  6. // (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the Do What The Fuck You Want To
  9. // Public License, Version 2, as published by Sam Hocevar. See
  10. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  11. //
  12. #if defined HAVE_CONFIG_H
  13. # include "config.h"
  14. #endif
  15. #include "../Include/LolBtPhysicsIntegration.h"
  16. #include "../Include/LolPhysics.h"
  17. #include "../Include/EasyCharacterController.h"
  18. #include "../Include/BulletCharacterController.h"
  19. //#include "LinearMath/btIDebugDraw.h"
  20. //#include "BulletCollision/CollisionDispatch/btGhostObject.h"
  21. //#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
  22. //#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
  23. //#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
  24. //#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
  25. //#include "LinearMath/btDefaultMotionState.h"
  26. namespace lol
  27. {
  28. namespace phys
  29. {
  30. #if 0
  31. #ifdef HAVE_PHYS_USE_BULLET
  32. // static helper method
  33. static btVector3
  34. getNormalizedVector(const btVector3& v)
  35. {
  36. btVector3 n = v.normalized();
  37. if (n.length() < SIMD_EPSILON) {
  38. n.setValue(0, 0, 0);
  39. }
  40. return n;
  41. }
  42. ///@todo Interact with dynamic objects,
  43. ///Ride kinematicly animated platforms properly
  44. ///More realistic (or maybe just a config option) falling
  45. /// -> Should integrate falling velocity manually and use that in stepDown()
  46. ///Support jumping
  47. ///Support ducking
  48. class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
  49. {
  50. public:
  51. btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
  52. {
  53. m_me = me;
  54. }
  55. virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
  56. {
  57. if (rayResult.m_collisionObject == m_me)
  58. return 1.0;
  59. return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
  60. }
  61. protected:
  62. btCollisionObject* m_me;
  63. };
  64. class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
  65. {
  66. public:
  67. btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
  68. : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
  69. , m_me(me)
  70. , m_up(up)
  71. , m_minSlopeDot(minSlopeDot)
  72. {
  73. }
  74. virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
  75. {
  76. if (convexResult.m_hitCollisionObject == m_me)
  77. return btScalar(1.0);
  78. btVector3 hitNormalWorld;
  79. if (normalInWorldSpace)
  80. {
  81. hitNormalWorld = convexResult.m_hitNormalLocal;
  82. } else
  83. {
  84. ///need to transform normal into worldspace
  85. hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
  86. }
  87. btScalar dotUp = m_up.dot(hitNormalWorld);
  88. if (dotUp < m_minSlopeDot) {
  89. return btScalar(1.0);
  90. }
  91. return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
  92. }
  93. protected:
  94. btCollisionObject* m_me;
  95. const btVector3 m_up;
  96. btScalar m_minSlopeDot;
  97. };
  98. /*
  99. * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
  100. *
  101. * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
  102. */
  103. btVector3 BulletKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal)
  104. {
  105. return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
  106. }
  107. /*
  108. * Returns the portion of 'direction' that is parallel to 'normal'
  109. */
  110. btVector3 BulletKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal)
  111. {
  112. btScalar magnitude = direction.dot(normal);
  113. return normal * magnitude;
  114. }
  115. /*
  116. * Returns the portion of 'direction' that is perpindicular to 'normal'
  117. */
  118. btVector3 BulletKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal)
  119. {
  120. return direction - parallelComponent(direction, normal);
  121. }
  122. BulletKinematicCharacterController::BulletKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis)
  123. {
  124. m_upAxis = upAxis;
  125. m_addedMargin = 0.02;
  126. m_walkDirection.setValue(0,0,0);
  127. m_useGhostObjectSweepTest = true;
  128. m_ghostObject = ghostObject;
  129. m_stepHeight = stepHeight;
  130. m_turnAngle = btScalar(0.0);
  131. m_convexShape=convexShape;
  132. m_useWalkDirection = true; // use walk direction by default, legacy behavior
  133. m_velocityTimeInterval = 0.0;
  134. m_verticalVelocity = 0.0;
  135. m_verticalOffset = 0.0;
  136. m_gravity = 9.8 * 3 ; // 3G acceleration.
  137. m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
  138. m_jumpSpeed = 10.0; // ?
  139. m_wasOnGround = false;
  140. m_wasJumping = false;
  141. setMaxSlope(btRadians(45.0));
  142. }
  143. BulletKinematicCharacterController::~BulletKinematicCharacterController ()
  144. {
  145. }
  146. btPairCachingGhostObject* BulletKinematicCharacterController::getGhostObject()
  147. {
  148. return m_ghostObject;
  149. }
  150. bool BulletKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld)
  151. {
  152. bool penetration = false;
  153. collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
  154. m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
  155. btScalar maxPen = btScalar(0.0);
  156. for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
  157. {
  158. m_manifoldArray.resize(0);
  159. btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
  160. if (collisionPair->m_algorithm)
  161. collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
  162. for (int j=0;j<m_manifoldArray.size();j++)
  163. {
  164. btPersistentManifold* manifold = m_manifoldArray[j];
  165. btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
  166. for (int p=0;p<manifold->getNumContacts();p++)
  167. {
  168. const btManifoldPoint&pt = manifold->getContactPoint(p);
  169. btScalar dist = pt.getDistance();
  170. if (dist < 0.0)
  171. {
  172. if (dist < maxPen)
  173. {
  174. maxPen = dist;
  175. m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
  176. }
  177. m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
  178. penetration = true;
  179. } else {
  180. //printf("touching %f\n", dist);
  181. }
  182. }
  183. //manifold->clearManifold();
  184. }
  185. }
  186. btTransform newTrans = m_ghostObject->getWorldTransform();
  187. newTrans.setOrigin(m_currentPosition);
  188. m_ghostObject->setWorldTransform(newTrans);
  189. // printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
  190. return penetration;
  191. }
  192. void BulletKinematicCharacterController::stepUp ( btCollisionWorld* world)
  193. {
  194. // phase 1: up
  195. btTransform start, end;
  196. m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f));
  197. start.setIdentity ();
  198. end.setIdentity ();
  199. /* FIXME: Handle penetration properly */
  200. start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin));
  201. end.setOrigin (m_targetPosition);
  202. btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071));
  203. callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
  204. callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
  205. if (m_useGhostObjectSweepTest)
  206. {
  207. m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
  208. }
  209. else
  210. {
  211. world->convexSweepTest (m_convexShape, start, end, callback);
  212. }
  213. if (callback.hasHit())
  214. {
  215. // Only modify the position if the hit was a slope and not a wall or ceiling.
  216. if(callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0)
  217. {
  218. // we moved up only a fraction of the step height
  219. m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
  220. m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
  221. }
  222. m_verticalVelocity = 0.0;
  223. m_verticalOffset = 0.0;
  224. } else {
  225. m_currentStepOffset = m_stepHeight;
  226. m_currentPosition = m_targetPosition;
  227. }
  228. }
  229. void BulletKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
  230. {
  231. btVector3 movementDirection = m_targetPosition - m_currentPosition;
  232. btScalar movementLength = movementDirection.length();
  233. if (movementLength>SIMD_EPSILON)
  234. {
  235. movementDirection.normalize();
  236. btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
  237. reflectDir.normalize();
  238. btVector3 parallelDir, perpindicularDir;
  239. parallelDir = parallelComponent (reflectDir, hitNormal);
  240. perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
  241. m_targetPosition = m_currentPosition;
  242. if (0)//tangentMag != 0.0)
  243. {
  244. btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
  245. // printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
  246. m_targetPosition += parComponent;
  247. }
  248. if (normalMag != 0.0)
  249. {
  250. btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
  251. // printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
  252. m_targetPosition += perpComponent;
  253. }
  254. } else
  255. {
  256. // printf("movementLength don't normalize a zero vector\n");
  257. }
  258. }
  259. void BulletKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove)
  260. {
  261. // printf("m_normalizedDirection=%f,%f,%f\n",
  262. // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
  263. // phase 2: forward and strafe
  264. btTransform start, end;
  265. m_targetPosition = m_currentPosition + walkMove;
  266. start.setIdentity ();
  267. end.setIdentity ();
  268. btScalar fraction = 1.0;
  269. btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
  270. // printf("distance2=%f\n",distance2);
  271. if (m_touchingContact)
  272. {
  273. if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0))
  274. {
  275. updateTargetPositionBasedOnCollision (m_touchingNormal);
  276. }
  277. }
  278. int maxIter = 10;
  279. while (fraction > btScalar(0.01) && maxIter-- > 0)
  280. {
  281. start.setOrigin (m_currentPosition);
  282. end.setOrigin (m_targetPosition);
  283. btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
  284. btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0));
  285. callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
  286. callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
  287. btScalar margin = m_convexShape->getMargin();
  288. m_convexShape->setMargin(margin + m_addedMargin);
  289. if (m_useGhostObjectSweepTest)
  290. {
  291. m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  292. } else
  293. {
  294. collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  295. }
  296. m_convexShape->setMargin(margin);
  297. fraction -= callback.m_closestHitFraction;
  298. if (callback.hasHit())
  299. {
  300. // we moved only a fraction
  301. btScalar hitDistance;
  302. hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
  303. // m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
  304. updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
  305. btVector3 currentDir = m_targetPosition - m_currentPosition;
  306. distance2 = currentDir.length2();
  307. if (distance2 > SIMD_EPSILON)
  308. {
  309. currentDir.normalize();
  310. /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
  311. if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
  312. {
  313. break;
  314. }
  315. } else
  316. {
  317. // printf("currentDir: don't normalize a zero vector\n");
  318. break;
  319. }
  320. } else {
  321. // we moved whole way
  322. m_currentPosition = m_targetPosition;
  323. }
  324. // if (callback.m_closestHitFraction == 0.f)
  325. // break;
  326. }
  327. }
  328. void BulletKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt)
  329. {
  330. btTransform start, end;
  331. // phase 3: down
  332. /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
  333. btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep);
  334. btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
  335. btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity;
  336. m_targetPosition -= (step_drop + gravity_drop);*/
  337. btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
  338. if(downVelocity > 0.0 && downVelocity < m_stepHeight
  339. && (m_wasOnGround || !m_wasJumping))
  340. {
  341. downVelocity = m_stepHeight;
  342. }
  343. btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
  344. m_targetPosition -= step_drop;
  345. start.setIdentity ();
  346. end.setIdentity ();
  347. start.setOrigin (m_currentPosition);
  348. end.setOrigin (m_targetPosition);
  349. btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine);
  350. callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
  351. callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
  352. if (m_useGhostObjectSweepTest)
  353. {
  354. m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  355. } else
  356. {
  357. collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  358. }
  359. if (callback.hasHit())
  360. {
  361. // we dropped a fraction of the height -> hit floor
  362. m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
  363. m_verticalVelocity = 0.0;
  364. m_verticalOffset = 0.0;
  365. m_wasJumping = false;
  366. } else {
  367. // we dropped the full height
  368. m_currentPosition = m_targetPosition;
  369. }
  370. }
  371. void BulletKinematicCharacterController::setWalkDirection
  372. (
  373. const btVector3& walkDirection
  374. )
  375. {
  376. m_useWalkDirection = true;
  377. m_walkDirection = walkDirection;
  378. m_normalizedDirection = getNormalizedVector(m_walkDirection);
  379. }
  380. void BulletKinematicCharacterController::setVelocityForTimeInterval
  381. (
  382. const btVector3& velocity,
  383. btScalar timeInterval
  384. )
  385. {
  386. // printf("setVelocity!\n");
  387. // printf(" interval: %f\n", timeInterval);
  388. // printf(" velocity: (%f, %f, %f)\n",
  389. // velocity.x(), velocity.y(), velocity.z());
  390. m_useWalkDirection = false;
  391. m_walkDirection = velocity;
  392. m_normalizedDirection = getNormalizedVector(m_walkDirection);
  393. m_velocityTimeInterval = timeInterval;
  394. }
  395. void BulletKinematicCharacterController::reset ()
  396. {
  397. }
  398. void BulletKinematicCharacterController::warp (const btVector3& origin)
  399. {
  400. btTransform xform;
  401. xform.setIdentity();
  402. xform.setOrigin (origin);
  403. m_ghostObject->setWorldTransform (xform);
  404. }
  405. void BulletKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld)
  406. {
  407. int numPenetrationLoops = 0;
  408. m_touchingContact = false;
  409. while (recoverFromPenetration (collisionWorld))
  410. {
  411. numPenetrationLoops++;
  412. m_touchingContact = true;
  413. if (numPenetrationLoops > 4)
  414. {
  415. //printf("character could not recover from penetration = %d\n", numPenetrationLoops);
  416. break;
  417. }
  418. }
  419. m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
  420. m_targetPosition = m_currentPosition;
  421. // printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
  422. }
  423. #include <stdio.h>
  424. void BulletKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt)
  425. {
  426. // printf("playerStep(): ");
  427. // printf(" dt = %f", dt);
  428. // quick check...
  429. if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) {
  430. // printf("\n");
  431. return; // no motion
  432. }
  433. m_wasOnGround = onGround();
  434. // Update fall velocity.
  435. m_verticalVelocity -= m_gravity * dt;
  436. if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
  437. {
  438. m_verticalVelocity = m_jumpSpeed;
  439. }
  440. if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
  441. {
  442. m_verticalVelocity = -btFabs(m_fallSpeed);
  443. }
  444. m_verticalOffset = m_verticalVelocity * dt;
  445. btTransform xform;
  446. xform = m_ghostObject->getWorldTransform ();
  447. // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
  448. // printf("walkSpeed=%f\n",walkSpeed);
  449. stepUp (collisionWorld);
  450. if (m_useWalkDirection) {
  451. stepForwardAndStrafe (collisionWorld, m_walkDirection);
  452. } else {
  453. //printf(" time: %f", m_velocityTimeInterval);
  454. // still have some time left for moving!
  455. btScalar dtMoving =
  456. (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval;
  457. m_velocityTimeInterval -= dt;
  458. // how far will we move while we are moving?
  459. btVector3 move = m_walkDirection * dtMoving;
  460. //printf(" dtMoving: %f", dtMoving);
  461. // okay, step
  462. stepForwardAndStrafe(collisionWorld, move);
  463. }
  464. stepDown (collisionWorld, dt);
  465. // printf("\n");
  466. xform.setOrigin (m_currentPosition);
  467. m_ghostObject->setWorldTransform (xform);
  468. }
  469. void BulletKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
  470. {
  471. m_fallSpeed = fallSpeed;
  472. }
  473. void BulletKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
  474. {
  475. m_jumpSpeed = jumpSpeed;
  476. }
  477. void BulletKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
  478. {
  479. m_maxJumpHeight = maxJumpHeight;
  480. }
  481. bool BulletKinematicCharacterController::canJump () const
  482. {
  483. return onGround();
  484. }
  485. void BulletKinematicCharacterController::jump ()
  486. {
  487. if (!canJump())
  488. return;
  489. m_verticalVelocity = m_jumpSpeed;
  490. m_wasJumping = true;
  491. #if 0
  492. currently no jumping.
  493. btTransform xform;
  494. m_rigidBody->getMotionState()->getWorldTransform (xform);
  495. btVector3 up = xform.getBasis()[1];
  496. up.normalize ();
  497. btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
  498. m_rigidBody->applyCentralImpulse (up * magnitude);
  499. #endif
  500. }
  501. void BulletKinematicCharacterController::setGravity(btScalar gravity)
  502. {
  503. m_gravity = gravity;
  504. }
  505. btScalar BulletKinematicCharacterController::getGravity() const
  506. {
  507. return m_gravity;
  508. }
  509. void BulletKinematicCharacterController::setMaxSlope(btScalar slopeRadians)
  510. {
  511. m_maxSlopeRadians = slopeRadians;
  512. m_maxSlopeCosine = btCos(slopeRadians);
  513. }
  514. btScalar BulletKinematicCharacterController::getMaxSlope() const
  515. {
  516. return m_maxSlopeRadians;
  517. }
  518. bool BulletKinematicCharacterController::onGround () const
  519. {
  520. return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0;
  521. }
  522. btVector3* BulletKinematicCharacterController::getUpAxisDirections()
  523. {
  524. static btVector3 sUpAxisDirection[3] = { btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f) };
  525. return sUpAxisDirection;
  526. }
  527. void BulletKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer)
  528. {
  529. }
  530. #endif // HAVE_PHYS_USE_BULLET
  531. #endif // 0
  532. } /* namespace phys */
  533. } /* namespace lol */