Bullet Collision Detection & Physics Library

btKinematicCharacterController.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2008 Erwin Coumans  http://bulletphysics.com
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 
00017 #include "LinearMath/btIDebugDraw.h"
00018 #include "BulletCollision/CollisionDispatch/btGhostObject.h"
00019 #include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
00020 #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
00021 #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
00022 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
00023 #include "LinearMath/btDefaultMotionState.h"
00024 #include "btKinematicCharacterController.h"
00025 
00026 
00027 // static helper method
00028 static btVector3
00029 getNormalizedVector(const btVector3& v)
00030 {
00031         btVector3 n = v.normalized();
00032         if (n.length() < SIMD_EPSILON) {
00033                 n.setValue(0, 0, 0);
00034         }
00035         return n;
00036 }
00037 
00038 
00045 class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
00046 {
00047 public:
00048         btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
00049         {
00050                 m_me = me;
00051         }
00052 
00053         virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
00054         {
00055                 if (rayResult.m_collisionObject == m_me)
00056                         return 1.0;
00057 
00058                 return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
00059         }
00060 protected:
00061         btCollisionObject* m_me;
00062 };
00063 
00064 class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
00065 {
00066 public:
00067         btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
00068         : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
00069         , m_me(me)
00070         , m_up(up)
00071         , m_minSlopeDot(minSlopeDot)
00072         {
00073         }
00074 
00075         virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
00076         {
00077                 if (convexResult.m_hitCollisionObject == m_me)
00078                         return btScalar(1.0);
00079 
00080                 btVector3 hitNormalWorld;
00081                 if (normalInWorldSpace)
00082                 {
00083                         hitNormalWorld = convexResult.m_hitNormalLocal;
00084                 } else
00085                 {
00087                         hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
00088                 }
00089 
00090                 btScalar dotUp = m_up.dot(hitNormalWorld);
00091                 if (dotUp < m_minSlopeDot) {
00092                         return btScalar(1.0);
00093                 }
00094 
00095                 return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
00096         }
00097 protected:
00098         btCollisionObject* m_me;
00099         const btVector3 m_up;
00100         btScalar m_minSlopeDot;
00101 };
00102 
00103 /*
00104  * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
00105  *
00106  * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
00107  */
00108 btVector3 btKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal)
00109 {
00110         return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
00111 }
00112 
00113 /*
00114  * Returns the portion of 'direction' that is parallel to 'normal'
00115  */
00116 btVector3 btKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal)
00117 {
00118         btScalar magnitude = direction.dot(normal);
00119         return normal * magnitude;
00120 }
00121 
00122 /*
00123  * Returns the portion of 'direction' that is perpindicular to 'normal'
00124  */
00125 btVector3 btKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal)
00126 {
00127         return direction - parallelComponent(direction, normal);
00128 }
00129 
00130 btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis)
00131 {
00132         m_upAxis = upAxis;
00133         m_addedMargin = 0.02;
00134         m_walkDirection.setValue(0,0,0);
00135         m_useGhostObjectSweepTest = true;
00136         m_ghostObject = ghostObject;
00137         m_stepHeight = stepHeight;
00138         m_turnAngle = btScalar(0.0);
00139         m_convexShape=convexShape;      
00140         m_useWalkDirection = true;      // use walk direction by default, legacy behavior
00141         m_velocityTimeInterval = 0.0;
00142         m_verticalVelocity = 0.0;
00143         m_verticalOffset = 0.0;
00144         m_gravity = 9.8 * 3 ; // 3G acceleration.
00145         m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
00146         m_jumpSpeed = 10.0; // ?
00147         m_wasOnGround = false;
00148         m_wasJumping = false;
00149         setMaxSlope(btRadians(45.0));
00150 }
00151 
00152 btKinematicCharacterController::~btKinematicCharacterController ()
00153 {
00154 }
00155 
00156 btPairCachingGhostObject* btKinematicCharacterController::getGhostObject()
00157 {
00158         return m_ghostObject;
00159 }
00160 
00161 bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld)
00162 {
00163 
00164         bool penetration = false;
00165 
00166         collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
00167 
00168         m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
00169         
00170         btScalar maxPen = btScalar(0.0);
00171         for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
00172         {
00173                 m_manifoldArray.resize(0);
00174 
00175                 btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
00176                 
00177                 if (collisionPair->m_algorithm)
00178                         collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
00179 
00180                 
00181                 for (int j=0;j<m_manifoldArray.size();j++)
00182                 {
00183                         btPersistentManifold* manifold = m_manifoldArray[j];
00184                         btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
00185                         for (int p=0;p<manifold->getNumContacts();p++)
00186                         {
00187                                 const btManifoldPoint&pt = manifold->getContactPoint(p);
00188 
00189                                 btScalar dist = pt.getDistance();
00190 
00191                                 if (dist < 0.0)
00192                                 {
00193                                         if (dist < maxPen)
00194                                         {
00195                                                 maxPen = dist;
00196                                                 m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
00197 
00198                                         }
00199                                         m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
00200                                         penetration = true;
00201                                 } else {
00202                                         //printf("touching %f\n", dist);
00203                                 }
00204                         }
00205                         
00206                         //manifold->clearManifold();
00207                 }
00208         }
00209         btTransform newTrans = m_ghostObject->getWorldTransform();
00210         newTrans.setOrigin(m_currentPosition);
00211         m_ghostObject->setWorldTransform(newTrans);
00212 //      printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
00213         return penetration;
00214 }
00215 
00216 void btKinematicCharacterController::stepUp ( btCollisionWorld* world)
00217 {
00218         // phase 1: up
00219         btTransform start, end;
00220         m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f));
00221 
00222         start.setIdentity ();
00223         end.setIdentity ();
00224 
00225         /* FIXME: Handle penetration properly */
00226         start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin));
00227         end.setOrigin (m_targetPosition);
00228 
00229         btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071));
00230         callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
00231         callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
00232         
00233         if (m_useGhostObjectSweepTest)
00234         {
00235                 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
00236         }
00237         else
00238         {
00239                 world->convexSweepTest (m_convexShape, start, end, callback);
00240         }
00241         
00242         if (callback.hasHit())
00243         {
00244                 // Only modify the position if the hit was a slope and not a wall or ceiling.
00245                 if(callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0)
00246                 {
00247                         // we moved up only a fraction of the step height
00248                         m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
00249                         m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
00250                 }
00251                 m_verticalVelocity = 0.0;
00252                 m_verticalOffset = 0.0;
00253         } else {
00254                 m_currentStepOffset = m_stepHeight;
00255                 m_currentPosition = m_targetPosition;
00256         }
00257 }
00258 
00259 void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
00260 {
00261         btVector3 movementDirection = m_targetPosition - m_currentPosition;
00262         btScalar movementLength = movementDirection.length();
00263         if (movementLength>SIMD_EPSILON)
00264         {
00265                 movementDirection.normalize();
00266 
00267                 btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
00268                 reflectDir.normalize();
00269 
00270                 btVector3 parallelDir, perpindicularDir;
00271 
00272                 parallelDir = parallelComponent (reflectDir, hitNormal);
00273                 perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
00274 
00275                 m_targetPosition = m_currentPosition;
00276                 if (0)//tangentMag != 0.0)
00277                 {
00278                         btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
00279 //                      printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
00280                         m_targetPosition +=  parComponent;
00281                 }
00282 
00283                 if (normalMag != 0.0)
00284                 {
00285                         btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
00286 //                      printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
00287                         m_targetPosition += perpComponent;
00288                 }
00289         } else
00290         {
00291 //              printf("movementLength don't normalize a zero vector\n");
00292         }
00293 }
00294 
00295 void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove)
00296 {
00297         // printf("m_normalizedDirection=%f,%f,%f\n",
00298         //      m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
00299         // phase 2: forward and strafe
00300         btTransform start, end;
00301         m_targetPosition = m_currentPosition + walkMove;
00302 
00303         start.setIdentity ();
00304         end.setIdentity ();
00305         
00306         btScalar fraction = 1.0;
00307         btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
00308 //      printf("distance2=%f\n",distance2);
00309 
00310         if (m_touchingContact)
00311         {
00312                 if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0))
00313                 {
00314                         updateTargetPositionBasedOnCollision (m_touchingNormal);
00315                 }
00316         }
00317 
00318         int maxIter = 10;
00319 
00320         while (fraction > btScalar(0.01) && maxIter-- > 0)
00321         {
00322                 start.setOrigin (m_currentPosition);
00323                 end.setOrigin (m_targetPosition);
00324                 btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
00325 
00326                 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0));
00327                 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
00328                 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
00329 
00330 
00331                 btScalar margin = m_convexShape->getMargin();
00332                 m_convexShape->setMargin(margin + m_addedMargin);
00333 
00334 
00335                 if (m_useGhostObjectSweepTest)
00336                 {
00337                         m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00338                 } else
00339                 {
00340                         collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00341                 }
00342                 
00343                 m_convexShape->setMargin(margin);
00344 
00345                 
00346                 fraction -= callback.m_closestHitFraction;
00347 
00348                 if (callback.hasHit())
00349                 {       
00350                         // we moved only a fraction
00351                         btScalar hitDistance;
00352                         hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
00353 
00354 //                      m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
00355 
00356                         updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
00357                         btVector3 currentDir = m_targetPosition - m_currentPosition;
00358                         distance2 = currentDir.length2();
00359                         if (distance2 > SIMD_EPSILON)
00360                         {
00361                                 currentDir.normalize();
00362                                 /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
00363                                 if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
00364                                 {
00365                                         break;
00366                                 }
00367                         } else
00368                         {
00369 //                              printf("currentDir: don't normalize a zero vector\n");
00370                                 break;
00371                         }
00372 
00373                 } else {
00374                         // we moved whole way
00375                         m_currentPosition = m_targetPosition;
00376                 }
00377 
00378         //      if (callback.m_closestHitFraction == 0.f)
00379         //              break;
00380 
00381         }
00382 }
00383 
00384 void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt)
00385 {
00386         btTransform start, end;
00387 
00388         // phase 3: down
00389         /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
00390         btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep);
00391         btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
00392         btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity; 
00393         m_targetPosition -= (step_drop + gravity_drop);*/
00394 
00395         btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
00396         if(downVelocity > 0.0 && downVelocity < m_stepHeight
00397                 && (m_wasOnGround || !m_wasJumping))
00398         {
00399                 downVelocity = m_stepHeight;
00400         }
00401 
00402         btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
00403         m_targetPosition -= step_drop;
00404 
00405         start.setIdentity ();
00406         end.setIdentity ();
00407 
00408         start.setOrigin (m_currentPosition);
00409         end.setOrigin (m_targetPosition);
00410 
00411         btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine);
00412         callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
00413         callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
00414         
00415         if (m_useGhostObjectSweepTest)
00416         {
00417                 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00418         } else
00419         {
00420                 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
00421         }
00422 
00423         if (callback.hasHit())
00424         {
00425                 // we dropped a fraction of the height -> hit floor
00426                 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
00427                 m_verticalVelocity = 0.0;
00428                 m_verticalOffset = 0.0;
00429                 m_wasJumping = false;
00430         } else {
00431                 // we dropped the full height
00432                 
00433                 m_currentPosition = m_targetPosition;
00434         }
00435 }
00436 
00437 
00438 
00439 void btKinematicCharacterController::setWalkDirection
00440 (
00441 const btVector3& walkDirection
00442 )
00443 {
00444         m_useWalkDirection = true;
00445         m_walkDirection = walkDirection;
00446         m_normalizedDirection = getNormalizedVector(m_walkDirection);
00447 }
00448 
00449 
00450 
00451 void btKinematicCharacterController::setVelocityForTimeInterval
00452 (
00453 const btVector3& velocity,
00454 btScalar timeInterval
00455 )
00456 {
00457 //      printf("setVelocity!\n");
00458 //      printf("  interval: %f\n", timeInterval);
00459 //      printf("  velocity: (%f, %f, %f)\n",
00460 //               velocity.x(), velocity.y(), velocity.z());
00461 
00462         m_useWalkDirection = false;
00463         m_walkDirection = velocity;
00464         m_normalizedDirection = getNormalizedVector(m_walkDirection);
00465         m_velocityTimeInterval = timeInterval;
00466 }
00467 
00468 
00469 
00470 void btKinematicCharacterController::reset ()
00471 {
00472 }
00473 
00474 void btKinematicCharacterController::warp (const btVector3& origin)
00475 {
00476         btTransform xform;
00477         xform.setIdentity();
00478         xform.setOrigin (origin);
00479         m_ghostObject->setWorldTransform (xform);
00480 }
00481 
00482 
00483 void btKinematicCharacterController::preStep (  btCollisionWorld* collisionWorld)
00484 {
00485         
00486         int numPenetrationLoops = 0;
00487         m_touchingContact = false;
00488         while (recoverFromPenetration (collisionWorld))
00489         {
00490                 numPenetrationLoops++;
00491                 m_touchingContact = true;
00492                 if (numPenetrationLoops > 4)
00493                 {
00494                         //printf("character could not recover from penetration = %d\n", numPenetrationLoops);
00495                         break;
00496                 }
00497         }
00498 
00499         m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
00500         m_targetPosition = m_currentPosition;
00501 //      printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
00502 
00503         
00504 }
00505 
00506 #include <stdio.h>
00507 
00508 void btKinematicCharacterController::playerStep (  btCollisionWorld* collisionWorld, btScalar dt)
00509 {
00510 //      printf("playerStep(): ");
00511 //      printf("  dt = %f", dt);
00512 
00513         // quick check...
00514         if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) {
00515 //              printf("\n");
00516                 return;         // no motion
00517         }
00518 
00519         m_wasOnGround = onGround();
00520 
00521         // Update fall velocity.
00522         m_verticalVelocity -= m_gravity * dt;
00523         if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
00524         {
00525                 m_verticalVelocity = m_jumpSpeed;
00526         }
00527         if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
00528         {
00529                 m_verticalVelocity = -btFabs(m_fallSpeed);
00530         }
00531         m_verticalOffset = m_verticalVelocity * dt;
00532 
00533 
00534         btTransform xform;
00535         xform = m_ghostObject->getWorldTransform ();
00536 
00537 //      printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
00538 //      printf("walkSpeed=%f\n",walkSpeed);
00539 
00540         stepUp (collisionWorld);
00541         if (m_useWalkDirection) {
00542                 stepForwardAndStrafe (collisionWorld, m_walkDirection);
00543         } else {
00544                 //printf("  time: %f", m_velocityTimeInterval);
00545                 // still have some time left for moving!
00546                 btScalar dtMoving =
00547                         (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval;
00548                 m_velocityTimeInterval -= dt;
00549 
00550                 // how far will we move while we are moving?
00551                 btVector3 move = m_walkDirection * dtMoving;
00552 
00553                 //printf("  dtMoving: %f", dtMoving);
00554 
00555                 // okay, step
00556                 stepForwardAndStrafe(collisionWorld, move);
00557         }
00558         stepDown (collisionWorld, dt);
00559 
00560         // printf("\n");
00561 
00562         xform.setOrigin (m_currentPosition);
00563         m_ghostObject->setWorldTransform (xform);
00564 }
00565 
00566 void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
00567 {
00568         m_fallSpeed = fallSpeed;
00569 }
00570 
00571 void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
00572 {
00573         m_jumpSpeed = jumpSpeed;
00574 }
00575 
00576 void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
00577 {
00578         m_maxJumpHeight = maxJumpHeight;
00579 }
00580 
00581 bool btKinematicCharacterController::canJump () const
00582 {
00583         return onGround();
00584 }
00585 
00586 void btKinematicCharacterController::jump ()
00587 {
00588         if (!canJump())
00589                 return;
00590 
00591         m_verticalVelocity = m_jumpSpeed;
00592         m_wasJumping = true;
00593 
00594 #if 0
00595         currently no jumping.
00596         btTransform xform;
00597         m_rigidBody->getMotionState()->getWorldTransform (xform);
00598         btVector3 up = xform.getBasis()[1];
00599         up.normalize ();
00600         btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
00601         m_rigidBody->applyCentralImpulse (up * magnitude);
00602 #endif
00603 }
00604 
00605 void btKinematicCharacterController::setGravity(btScalar gravity)
00606 {
00607         m_gravity = gravity;
00608 }
00609 
00610 btScalar btKinematicCharacterController::getGravity() const
00611 {
00612         return m_gravity;
00613 }
00614 
00615 void btKinematicCharacterController::setMaxSlope(btScalar slopeRadians)
00616 {
00617         m_maxSlopeRadians = slopeRadians;
00618         m_maxSlopeCosine = btCos(slopeRadians);
00619 }
00620 
00621 btScalar btKinematicCharacterController::getMaxSlope() const
00622 {
00623         return m_maxSlopeRadians;
00624 }
00625 
00626 bool btKinematicCharacterController::onGround () const
00627 {
00628         return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0;
00629 }
00630 
00631 
00632 btVector3* btKinematicCharacterController::getUpAxisDirections()
00633 {
00634         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) };
00635         
00636         return sUpAxisDirection;
00637 }
00638 
00639 void btKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer)
00640 {
00641 }