More KinematicCharacterController work.

This commit is contained in:
john.mccutchan
2008-07-03 22:27:49 +00:00
parent 65116fd3d3
commit a7f9bb8c8a
6 changed files with 163 additions and 71 deletions

View File

@@ -15,14 +15,18 @@ public:
virtual void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25, btScalar stepHeight = 0.25) = 0; virtual void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25, btScalar stepHeight = 0.25) = 0;
virtual void destroy (btDynamicsWorld* dynamicsWorld) = 0; virtual void destroy (btDynamicsWorld* dynamicsWorld) = 0;
virtual btRigidBody* getRigidBody () = 0; virtual btCollisionObject* getCollisionObject () = 0;
virtual void reset () = 0;
virtual void warp (const btVector3& origin) = 0;
virtual void preStep (btDynamicsWorld* dynamicsWorld) = 0; virtual void preStep (btDynamicsWorld* dynamicsWorld) = 0;
virtual void playerStep (btDynamicsWorld* dynamicsWorld, btScalar dt, virtual void playerStep (btDynamicsWorld* dynamicsWorld, btScalar dt,
int forward, int forward,
int backward, int backward,
int left, int left,
int right) = 0; int right,
int jump) = 0;
virtual bool canJump () const = 0; virtual bool canJump () const = 0;
virtual void jump () = 0; virtual void jump () = 0;

View File

@@ -159,6 +159,15 @@ class MyCustomOverlappingPairCallback : public btOverlappingPairCallback
btHashedOverlappingPairCache* m_hashPairCache; btHashedOverlappingPairCache* m_hashPairCache;
struct customOverlapFilterCallback : public btOverlapFilterCallback
{
bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
{
// we already know that the character proxy is either proxy0 or proxy1
return true;
}
} myCustomOverlapFilterCallback;
public: public:
MyCustomOverlappingPairCallback(CharacterDemo* demo,btCollisionObject* characterCollider) MyCustomOverlappingPairCallback(CharacterDemo* demo,btCollisionObject* characterCollider)
@@ -166,6 +175,7 @@ public:
m_characterCollider(characterCollider) m_characterCollider(characterCollider)
{ {
m_hashPairCache = new btHashedOverlappingPairCache(); m_hashPairCache = new btHashedOverlappingPairCache();
m_hashPairCache->setOverlapFilterCallback (&myCustomOverlapFilterCallback);
} }
virtual ~MyCustomOverlappingPairCallback() virtual ~MyCustomOverlappingPairCallback()
@@ -177,7 +187,7 @@ public:
{ {
if (proxy0->m_clientObject==m_characterCollider || proxy1->m_clientObject==m_characterCollider) if (proxy0->m_clientObject==m_characterCollider || proxy1->m_clientObject==m_characterCollider)
{ {
printf("addOverlappingPair (%x,%x)\n",proxy0,proxy1); //printf("addOverlappingPair (%p,%p)\n",proxy0,proxy1);
return m_hashPairCache->addOverlappingPair(proxy0,proxy1); return m_hashPairCache->addOverlappingPair(proxy0,proxy1);
} }
return 0; return 0;
@@ -187,7 +197,7 @@ public:
{ {
if (proxy0->m_clientObject==m_characterCollider || proxy1->m_clientObject==m_characterCollider) if (proxy0->m_clientObject==m_characterCollider || proxy1->m_clientObject==m_characterCollider)
{ {
printf("removeOverlappingPair (%x,%x)\n",proxy0,proxy1); //printf("removeOverlappingPair (%p,%p)\n",proxy0,proxy1);
return m_hashPairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); return m_hashPairCache->removeOverlappingPair(proxy0,proxy1,dispatcher);
} }
return 0; return 0;
@@ -197,7 +207,7 @@ public:
{ {
if (proxy0->m_clientObject==m_characterCollider) if (proxy0->m_clientObject==m_characterCollider)
{ {
printf("removeOverlappingPairsContainingProxy (%x)\n",proxy0); //printf("removeOverlappingPairsContainingProxy (%p)\n",proxy0);
m_hashPairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher); m_hashPairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher);
} }
} }
@@ -469,12 +479,9 @@ const float TRIANGLE_SIZE=20.f;
#endif #endif
m_character->setup (m_dynamicsWorld); m_character->setup (m_dynamicsWorld);
//we need to remove the rigid body from the broadphase in order to register all collisions
m_dynamicsWorld->removeRigidBody(m_character->getRigidBody());
//some custom callback sample //some custom callback sample
m_customPairCallback = new MyCustomOverlappingPairCallback(this,m_character->getRigidBody()); m_customPairCallback = new MyCustomOverlappingPairCallback(this,m_character->getCollisionObject());
sweepBP->setOverlappingPairUserCallback(m_customPairCallback); sweepBP->setOverlappingPairUserCallback(m_customPairCallback);
m_dynamicsWorld->addRigidBody(m_character->getRigidBody());
m_character->registerPairCache (m_customPairCallback->getOverlappingPairCache()); m_character->registerPairCache (m_customPairCallback->getOverlappingPairCache());
clientResetScene(); clientResetScene();
@@ -502,14 +509,10 @@ void CharacterDemo::clientMoveAndDisplay()
if (m_character) if (m_character)
{ {
m_character->preStep (m_dynamicsWorld); m_character->preStep (m_dynamicsWorld);
m_character->playerStep (m_dynamicsWorld, dt, gForward, gBackward, gLeft, gRight); m_character->playerStep (m_dynamicsWorld, dt, gForward, gBackward, gLeft, gRight, gJump);
if (gJump)
{
gJump = 0;
m_character->jump ();
}
} }
#if 0
printf("numPairs = %d\n",m_customPairCallback->getOverlappingPairArray().size()); printf("numPairs = %d\n",m_customPairCallback->getOverlappingPairArray().size());
{ {
btManifoldArray manifoldArray; btManifoldArray manifoldArray;
@@ -520,6 +523,9 @@ void CharacterDemo::clientMoveAndDisplay()
const btBroadphasePair& pair = m_customPairCallback->getOverlappingPairArray()[i]; const btBroadphasePair& pair = m_customPairCallback->getOverlappingPairArray()[i];
btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1); btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
if (!collisionPair)
continue;
if (collisionPair->m_algorithm) if (collisionPair->m_algorithm)
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
@@ -535,6 +541,7 @@ void CharacterDemo::clientMoveAndDisplay()
} }
} }
} }
#endif
@@ -610,20 +617,12 @@ void CharacterDemo::displayCallback(void)
glutSwapBuffers(); glutSwapBuffers();
} }
void CharacterDemo::clientResetScene() void CharacterDemo::clientResetScene()
{ {
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_character->getRigidBody()->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher()); m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_character->getCollisionObject()->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
btTransform startTransform; m_character->reset ();
startTransform.setIdentity (); m_character->warp (btVector3(0.0, 1.75, 0.0));
startTransform.setOrigin (btVector3(0.0, 2.0, 0.0));
m_character->getRigidBody()->getMotionState()->setWorldTransform(startTransform);
m_character->getRigidBody()->setLinearVelocity(btVector3(0,0,0));
m_character->getRigidBody()->setAngularVelocity(btVector3(0,0,0));
} }
void CharacterDemo::specialKeyboardUp(int key, int x, int y) void CharacterDemo::specialKeyboardUp(int key, int x, int y)
@@ -715,14 +714,14 @@ void CharacterDemo::updateCamera()
btTransform characterWorldTrans; btTransform characterWorldTrans;
//look at the vehicle //look at the vehicle
m_character->getRigidBody()->getMotionState()->getWorldTransform(characterWorldTrans); characterWorldTrans = m_character->getCollisionObject()->getWorldTransform();
btVector3 up = characterWorldTrans.getBasis()[1]; btVector3 up = characterWorldTrans.getBasis()[1];
btVector3 backward = -characterWorldTrans.getBasis()[2]; btVector3 backward = -characterWorldTrans.getBasis()[2];
up.normalize (); up.normalize ();
backward.normalize (); backward.normalize ();
m_cameraTargetPosition = characterWorldTrans.getOrigin(); m_cameraTargetPosition = characterWorldTrans.getOrigin();
m_cameraPosition = m_cameraTargetPosition + up * 5.0 + backward * 5.0; m_cameraPosition = m_cameraTargetPosition + up * 2.0 + backward * 2.0;
//update OpenGL camera settings //update OpenGL camera settings
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);

View File

@@ -62,7 +62,7 @@ void DynamicCharacterController::destroy (btDynamicsWorld* dynamicsWorld)
} }
} }
btRigidBody* DynamicCharacterController::getRigidBody () btCollisionObject* DynamicCharacterController::getCollisionObject ()
{ {
return m_rigidBody; return m_rigidBody;
} }
@@ -122,7 +122,8 @@ void DynamicCharacterController::playerStep (btScalar dt,
int forward, int forward,
int backward, int backward,
int left, int left,
int right) int right,
int jump)
{ {
btTransform xform; btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform); m_rigidBody->getMotionState()->getWorldTransform (xform);

View File

@@ -32,14 +32,15 @@ public:
void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25, btScalar stepHeight = 0.25); void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25, btScalar stepHeight = 0.25);
void destroy (btDynamicsWorld* dynamicsWorld); void destroy (btDynamicsWorld* dynamicsWorld);
btRigidBody* getRigidBody (); btCollisionObject* getCollisionObject ();
void preStep (btDynamicsWorld* dynamicsWorld); void preStep (btDynamicsWorld* dynamicsWorld);
void playerStep (btScalar dt, void playerStep (btScalar dt,
int forward, int forward,
int backward, int backward,
int left, int left,
int right); int right,
int jump);
bool canJump () const; bool canJump () const;
void jump (); void jump ();

View File

@@ -11,16 +11,18 @@
#include "KinematicCharacterController.h" #include "KinematicCharacterController.h"
/* TODO: /* TODO:
* Handle projecting/slide along surfaces * Fix jitter
* Deal with starting in penetration
* Interact with dynamic objects * Interact with dynamic objects
* Ride kinematicly animated platforms properly * Ride kinematicly animated platforms properly
* Step climbing * More realistic (or maybe just a config option) falling
* -> Should integrate falling velocity manually and use that in stepDown()
* Support jumping
* Support ducking
*/ */
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{ {
public: public:
ClosestNotMeRayResultCallback (btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) ClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
{ {
m_me = me; m_me = me;
} }
@@ -33,13 +35,13 @@ public:
return ClosestRayResultCallback::AddSingleResult (rayResult, normalInWorldSpace); return ClosestRayResultCallback::AddSingleResult (rayResult, normalInWorldSpace);
} }
protected: protected:
btRigidBody* m_me; btCollisionObject* m_me;
}; };
class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
{ {
public: public:
ClosestNotMeConvexResultCallback (btRigidBody* me) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) ClosestNotMeConvexResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
{ {
m_me = me; m_me = me;
} }
@@ -52,7 +54,7 @@ public:
return ClosestConvexResultCallback::AddSingleResult (convexResult, normalInWorldSpace); return ClosestConvexResultCallback::AddSingleResult (convexResult, normalInWorldSpace);
} }
protected: protected:
btRigidBody* m_me; btCollisionObject* m_me;
}; };
/* /*
@@ -88,7 +90,7 @@ KinematicCharacterController::KinematicCharacterController ()
m_walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s m_walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
m_shape = NULL; m_shape = NULL;
m_pairCache = NULL; m_pairCache = NULL;
m_rigidBody = NULL; m_collisionObject = NULL;
} }
KinematicCharacterController::~KinematicCharacterController () KinematicCharacterController::~KinematicCharacterController ()
@@ -116,19 +118,18 @@ void KinematicCharacterController::setup (btDynamicsWorld* dynamicsWorld, btScal
startTransform.setOrigin (btVector3(0.0, 4.0, 0.0)); startTransform.setOrigin (btVector3(0.0, 4.0, 0.0));
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape); btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
m_rigidBody = new btRigidBody(cInfo); m_collisionObject = new btCollisionObject ();
m_rigidBody->setCollisionFlags( m_rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE); m_collisionObject->setCollisionShape (m_shape);
m_rigidBody->setSleepingThresholds (0.0, 0.0); m_collisionObject->setCollisionFlags (btCollisionObject::CF_KINEMATIC_OBJECT);
m_rigidBody->setAngularFactor (0.0); dynamicsWorld->addCollisionObject (m_collisionObject);
dynamicsWorld->addRigidBody (m_rigidBody);
} }
void KinematicCharacterController::destroy (btDynamicsWorld* dynamicsWorld) void KinematicCharacterController::destroy (btDynamicsWorld* dynamicsWorld)
{ {
if (m_rigidBody) if (m_collisionObject)
{ {
dynamicsWorld->removeRigidBody (m_rigidBody); dynamicsWorld->removeCollisionObject (m_collisionObject);
delete m_rigidBody; delete m_collisionObject;
} }
if (m_shape) if (m_shape)
@@ -137,23 +138,24 @@ void KinematicCharacterController::destroy (btDynamicsWorld* dynamicsWorld)
} }
} }
btRigidBody* KinematicCharacterController::getRigidBody () btCollisionObject* KinematicCharacterController::getCollisionObject ()
{ {
return m_rigidBody; return m_collisionObject;
} }
void KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dynamicsWorld) bool KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dynamicsWorld)
{ {
if (m_pairCache == NULL) if (m_pairCache == NULL)
return; return false;
printf("%d\n", m_pairCache->getNumOverlappingPairs()); bool penetration = false;
dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs (m_pairCache, dynamicsWorld->getDispatchInfo(), dynamicsWorld->getDispatcher()); dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs (m_pairCache, dynamicsWorld->getDispatchInfo(), dynamicsWorld->getDispatcher());
btManifoldArray manifoldArray; btManifoldArray manifoldArray;
btScalar maxPen = btScalar(0.0);
for (int i = 0; i < m_pairCache->getNumOverlappingPairs(); i++) for (int i = 0; i < m_pairCache->getNumOverlappingPairs(); i++)
{ {
printf("%d\n",i);
manifoldArray.clear(); manifoldArray.clear();
btBroadphasePair* collisionPair = &m_pairCache->getOverlappingPairArray()[i]; btBroadphasePair* collisionPair = &m_pairCache->getOverlappingPairArray()[i];
@@ -164,19 +166,28 @@ void KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dyna
for (int j=0;j<manifoldArray.size();j++) for (int j=0;j<manifoldArray.size();j++)
{ {
btPersistentManifold* manifold = manifoldArray[j]; btPersistentManifold* manifold = manifoldArray[j];
btScalar directionSign = manifold->getBody0() == m_collisionObject ? btScalar(-1.0) : btScalar(1.0);
for (int p=0;p<manifold->getNumContacts();p++) for (int p=0;p<manifold->getNumContacts();p++)
{ {
const btManifoldPoint&pt = manifold->getContactPoint(p); const btManifoldPoint&pt = manifold->getContactPoint(p);
if (pt.getDistance() < 0.0) if (pt.getDistance() < 0.0)
{ {
printf("penetration %f\n", pt.getDistance()); if (pt.getDistance() < maxPen)
{
maxPen = pt.getDistance();
m_touchingNormal = pt.m_normalWorldOnB * directionSign;
}
m_currentPosition += pt.m_normalWorldOnB * directionSign * pt.getDistance() * btScalar(0.2);
penetration = true;
} else { } else {
printf("touching %f\n", pt.getDistance()); //printf("touching %f\n", pt.getDistance());
} }
} }
manifold->clearManifold();
} }
} }
return penetration;
} }
void KinematicCharacterController::stepUp (btDynamicsWorld* dynamicsWorld) void KinematicCharacterController::stepUp (btDynamicsWorld* dynamicsWorld)
@@ -192,7 +203,7 @@ void KinematicCharacterController::stepUp (btDynamicsWorld* dynamicsWorld)
start.setOrigin (m_currentPosition + btVector3(btScalar(0.0), btScalar(0.1), btScalar(0.0))); start.setOrigin (m_currentPosition + btVector3(btScalar(0.0), btScalar(0.1), btScalar(0.0)));
end.setOrigin (m_targetPosition); end.setOrigin (m_targetPosition);
ClosestNotMeConvexResultCallback callback (m_rigidBody); ClosestNotMeConvexResultCallback callback (m_collisionObject);
dynamicsWorld->convexSweepTest (m_shape, start, end, callback); dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
@@ -235,6 +246,7 @@ void KinematicCharacterController::updateTargetPositionBasedOnCollision (const b
void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove) void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove)
{ {
btVector3 originalDir = walkMove.normalized();
// phase 2: forward and strafe // phase 2: forward and strafe
btTransform start, end; btTransform start, end;
m_targetPosition = m_currentPosition + walkMove; m_targetPosition = m_currentPosition + walkMove;
@@ -244,12 +256,18 @@ void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynami
btScalar fraction = 1.0; btScalar fraction = 1.0;
btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
if (m_touchingContact)
{
if (originalDir.dot(m_touchingNormal) > btScalar(0.0))
updateTargetPositionBasedOnCollision (m_touchingNormal);
}
while (fraction > btScalar(0.01)) while (fraction > btScalar(0.01))
{ {
start.setOrigin (m_currentPosition); start.setOrigin (m_currentPosition);
end.setOrigin (m_targetPosition); end.setOrigin (m_targetPosition);
ClosestNotMeConvexResultCallback callback (m_rigidBody); ClosestNotMeConvexResultCallback callback (m_collisionObject);
dynamicsWorld->convexSweepTest (m_shape, start, end, callback); dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
fraction -= callback.m_closestHitFraction; fraction -= callback.m_closestHitFraction;
@@ -257,9 +275,23 @@ void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynami
if (callback.HasHit()) if (callback.HasHit())
{ {
// we moved only a fraction // we moved only a fraction
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); btScalar hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
/* If the distance is farther than the collision margin, move */
if (hitDistance > 0.05)
{
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
}
updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld); updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
distance2 = (m_currentPosition-m_targetPosition).length2(); btVector3 currentDir = m_targetPosition - m_currentPosition;
distance2 = currentDir.length2();
currentDir.normalize();
/* Ageia's C.C. took this test from Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
if (currentDir.dot(originalDir) <= btScalar(0.0))
{
break;
}
} else { } else {
// we moved whole way // we moved whole way
m_currentPosition = m_targetPosition; m_currentPosition = m_targetPosition;
@@ -282,7 +314,7 @@ void KinematicCharacterController::stepDown (btDynamicsWorld* dynamicsWorld, btS
start.setOrigin (m_currentPosition); start.setOrigin (m_currentPosition);
end.setOrigin (m_targetPosition); end.setOrigin (m_targetPosition);
ClosestNotMeConvexResultCallback callback (m_rigidBody); ClosestNotMeConvexResultCallback callback (m_collisionObject);
dynamicsWorld->convexSweepTest (m_shape, start, end, callback); dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
@@ -297,6 +329,18 @@ void KinematicCharacterController::stepDown (btDynamicsWorld* dynamicsWorld, btS
} }
} }
void KinematicCharacterController::reset ()
{
}
void KinematicCharacterController::warp (const btVector3& origin)
{
btTransform xform;
xform.setIdentity();
xform.setOrigin (origin);
m_collisionObject->setWorldTransform (xform);
}
void KinematicCharacterController::registerPairCache (btOverlappingPairCache* pairCache) void KinematicCharacterController::registerPairCache (btOverlappingPairCache* pairCache)
{ {
m_pairCache = pairCache; m_pairCache = pairCache;
@@ -304,8 +348,20 @@ void KinematicCharacterController::registerPairCache (btOverlappingPairCache* pa
void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld) void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
{ {
int numPenetrationLoops = 0;
m_touchingContact = false;
while (recoverFromPenetration (dynamicsWorld))
{
numPenetrationLoops++;
m_touchingContact = true;
if (numPenetrationLoops > 4)
{
printf("character could not recover from penetration = %d\n", numPenetrationLoops);
break;
}
}
btTransform xform; btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform); xform = m_collisionObject->getWorldTransform ();
btVector3 forwardDir = xform.getBasis()[2]; btVector3 forwardDir = xform.getBasis()[2];
btVector3 upDir = xform.getBasis()[1]; btVector3 upDir = xform.getBasis()[1];
@@ -320,7 +376,8 @@ void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
m_currentPosition = xform.getOrigin(); m_currentPosition = xform.getOrigin();
m_targetPosition = m_currentPosition; m_targetPosition = m_currentPosition;
recoverFromPenetration (dynamicsWorld);
} }
void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld, void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld,
@@ -328,7 +385,8 @@ void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld,
int forward, int forward,
int backward, int backward,
int left, int left,
int right) int right,
int jump)
{ {
btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
btScalar walkSpeed = m_walkVelocity * dt; btScalar walkSpeed = m_walkVelocity * dt;
@@ -346,15 +404,29 @@ void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld,
walkDirection -= m_forwardDirection; walkDirection -= m_forwardDirection;
btTransform xform; btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform); xform = m_collisionObject->getWorldTransform ();
stepUp (dynamicsWorld); stepUp (dynamicsWorld);
stepForwardAndStrafe (dynamicsWorld, walkDirection * walkSpeed); stepForwardAndStrafe (dynamicsWorld, walkDirection * walkSpeed);
stepDown (dynamicsWorld, dt); stepDown (dynamicsWorld, dt);
xform.setOrigin (m_currentPosition); xform.setOrigin (m_currentPosition);
m_rigidBody->getMotionState()->setWorldTransform (xform); m_collisionObject->setWorldTransform (xform);
m_rigidBody->setCenterOfMassTransform (xform); }
void KinematicCharacterController::setFallSpeed (btScalar fallSpeed)
{
m_fallSpeed = fallSpeed;
}
void KinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
{
m_jumpSpeed = jumpSpeed;
}
void KinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
{
m_maxJumpHeight = maxJumpHeight;
} }
bool KinematicCharacterController::canJump () const bool KinematicCharacterController::canJump () const

View File

@@ -14,9 +14,13 @@ class KinematicCharacterController : public CharacterControllerInterface
protected: protected:
btScalar m_halfHeight; btScalar m_halfHeight;
btConvexShape* m_shape; btConvexShape* m_shape;
btRigidBody* m_rigidBody; btCollisionObject* m_collisionObject;
btOverlappingPairCache* m_pairCache; btOverlappingPairCache* m_pairCache;
btScalar m_fallSpeed;
btScalar m_jumpSpeed;
btScalar m_maxJumpHeight;
btScalar m_turnAngle; btScalar m_turnAngle;
btScalar m_walkVelocity; btScalar m_walkVelocity;
@@ -31,8 +35,11 @@ protected:
btVector3 m_currentPosition; btVector3 m_currentPosition;
btScalar m_currentStepOffset; btScalar m_currentStepOffset;
btVector3 m_targetPosition; btVector3 m_targetPosition;
bool m_touchingContact;
btVector3 m_touchingNormal;
void recoverFromPenetration (btDynamicsWorld* dynamicsWorld); bool recoverFromPenetration (btDynamicsWorld* dynamicsWorld);
void stepUp (btDynamicsWorld* dynamicsWorld); void stepUp (btDynamicsWorld* dynamicsWorld);
void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(1.0), btScalar normalMag = btScalar(0.0)); void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(1.0), btScalar normalMag = btScalar(0.0));
void stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove); void stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove);
@@ -43,7 +50,10 @@ public:
void setup (btDynamicsWorld* dynamicsWorld, btScalar height = btScalar(1.75), btScalar width = btScalar(0.4), btScalar stepHeight = btScalar(0.35)); void setup (btDynamicsWorld* dynamicsWorld, btScalar height = btScalar(1.75), btScalar width = btScalar(0.4), btScalar stepHeight = btScalar(0.35));
void destroy (btDynamicsWorld* dynamicsWorld); void destroy (btDynamicsWorld* dynamicsWorld);
btRigidBody* getRigidBody (); btCollisionObject* getCollisionObject ();
void reset ();
void warp (const btVector3& origin);
void registerPairCache (btOverlappingPairCache* pairCache); void registerPairCache (btOverlappingPairCache* pairCache);
void preStep (btDynamicsWorld* dynamicsWorld); void preStep (btDynamicsWorld* dynamicsWorld);
@@ -51,7 +61,12 @@ public:
int forward, int forward,
int backward, int backward,
int left, int left,
int right); int right,
int jump);
void setFallSpeed (btScalar fallSpeed);
void setJumpSpeed (btScalar jumpSpeed);
void setMaxJumpHeight (btScalar maxJumpHeight);
bool canJump () const; bool canJump () const;
void jump (); void jump ();