Abstracted character controller interface

Renamed old character controller to DynamicCharacterController
First start at KinematicCharacterController. Still has bugs.
This commit is contained in:
john.mccutchan
2008-07-02 23:19:02 +00:00
parent db146019f1
commit de1f2631f4
7 changed files with 626 additions and 31 deletions

View File

@@ -0,0 +1,32 @@
#ifndef CHARACTER_CONTROLLER_INTERFACE_H
#define CHARACTER_CONTROLLER_INTERFACE_H
#include "LinearMath/btVector3.h"
class btCollisionShape;
class btRigidBody;
class btDynamicsWorld;
class CharacterControllerInterface
{
public:
CharacterControllerInterface () {};
virtual ~CharacterControllerInterface () {};
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 btRigidBody* getRigidBody () = 0;
virtual void preStep (btDynamicsWorld* dynamicsWorld) = 0;
virtual void playerStep (btDynamicsWorld* dynamicsWorld, btScalar dt,
int forward,
int backward,
int left,
int right) = 0;
virtual bool canJump () const = 0;
virtual void jump () = 0;
virtual bool onGround () const = 0;
};
#endif

View File

@@ -28,7 +28,11 @@ subject to the following restrictions:
#include "GlutStuff.h"
#include "CharacterDemo.h"
#include "CharacterController.h"
#ifdef DYNAMIC_CHARACTER_CONTROLLER
#include "DynamicCharacterController.h"
#else
#include "KinematicCharacterController.h"
#endif
const int maxProxies = 32766;
const int maxOverlap = 65535;
@@ -39,6 +43,55 @@ static int gLeft = 0;
static int gRight = 0;
static int gJump = 0;
#define QUAKE_BSP_IMPORTING 1
#ifdef QUAKE_BSP_IMPORTING
#include "Demos/BspDemo/BspLoader.h"
#include "Demos/BspDemo/BspConverter.h"
#endif //QUAKE_BSP_IMPORTING
class BspToBulletConverter : public BspConverter
{
CharacterDemo* m_demoApp;
public:
BspToBulletConverter(CharacterDemo* demoApp)
:m_demoApp(demoApp)
{
}
virtual void addConvexVerticesCollider(btAlignedObjectArray<btVector3>& vertices, bool isEntity, const btVector3& entityTargetLocation)
{
///perhaps we can do something special with entities (isEntity)
///like adding a collision Triggering (as example)
if (vertices.size() > 0)
{
float mass = 0.f;
btTransform startTransform;
//can use a shift
startTransform.setIdentity();
startTransform.setOrigin(btVector3(0,-10.0f,0.0f));
//this create an internal copy of the vertices
for (int i = 0; i < vertices.size(); i++)
{
vertices[i] *= btScalar(0.5);
float t = vertices[i].getZ() * btScalar(0.75);
vertices[i].setZ(-vertices[i].getY());
vertices[i].setY(t);
}
btCollisionShape* shape = new btConvexHullShape(&(vertices[0].getX()),vertices.size());
m_demoApp->m_collisionShapes.push_back(shape);
//btRigidBody* body = m_demoApp->localCreateRigidBody(mass, startTransform,shape);
m_demoApp->localCreateRigidBody(mass, startTransform,shape);
}
}
};
CharacterDemo::CharacterDemo()
:
m_cameraHeight(4.f),
@@ -57,6 +110,7 @@ CharacterDemo::~CharacterDemo()
if (m_character)
m_character->destroy (m_dynamicsWorld);
//remove the rigidbodies from the dynamics world and delete them
int i;
for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
@@ -153,11 +207,15 @@ public:
return m_hashPairCache->getOverlappingPairArray();
}
btOverlappingPairCache* getOverlappingPairCache()
{
return m_hashPairCache;
}
};
void CharacterDemo::initPhysics()
{
btCollisionShape* groundShape = new btBoxShape(btVector3(50,3,50));
m_collisionShapes.push_back(groundShape);
m_collisionConfiguration = new btDefaultCollisionConfiguration();
@@ -173,7 +231,53 @@ void CharacterDemo::initPhysics()
btTransform tr;
tr.setIdentity();
//either use heightfield or triangle mesh
#define USE_BSP_STAGE
#ifdef USE_BSP_STAGE
#ifdef QUAKE_BSP_IMPORTING
char* bspfilename = "BspDemo.bsp";
void* memoryBuffer = 0;
FILE* file = fopen(bspfilename,"r");
if (!file)
{
//try again other path,
//sight... visual studio leaves the current working directory in the projectfiles folder
//instead of executable folder. who wants this default behaviour?!?
bspfilename = "../../BspDemo.bsp";
file = fopen(bspfilename,"r");
}
if (!file)
{
//try again other path,
//sight... visual studio leaves the current working directory in the projectfiles folder
//instead of executable folder. who wants this default behaviour?!?
bspfilename = "BspDemo.bsp";
file = fopen(bspfilename,"r");
}
if (file)
{
BspLoader bspLoader;
int size=0;
if (fseek(file, 0, SEEK_END) || (size = ftell(file)) == EOF || fseek(file, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
printf("Error: cannot get filesize from %s\n", bspfilename);
} else
{
//how to detect file size?
memoryBuffer = malloc(size+1);
fread(memoryBuffer,1,size,file);
bspLoader.loadBSPFile( memoryBuffer);
BspToBulletConverter bsp2bullet(this);
float bspScaling = 0.1f;
bsp2bullet.convertBsp(bspLoader,bspScaling);
}
fclose(file);
}
#endif
#else
#define USE_TRIMESH_GROUND 1
#ifdef USE_TRIMESH_GROUND
int i;
@@ -297,15 +401,6 @@ const float TRIANGLE_SIZE=20.f;
//create ground object
localCreateRigidBody(0,tr,groundShape);
m_character = new CharacterController ();
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
m_customPairCallback = new MyCustomOverlappingPairCallback(this,m_character->getRigidBody());
sweepBP->setOverlappingPairUserCallback(m_customPairCallback);
m_dynamicsWorld->addRigidBody(m_character->getRigidBody());
#define CUBE_HALF_EXTENTS 0.5
@@ -365,6 +460,22 @@ const float TRIANGLE_SIZE=20.f;
}
#endif
#endif
#ifdef DYNAMIC_CHARACTER_CONTROLLER
m_character = new DynamicCharacterController ();
#else
m_character = new KinematicCharacterController ();
#endif
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
m_customPairCallback = new MyCustomOverlappingPairCallback(this,m_character->getRigidBody());
sweepBP->setOverlappingPairUserCallback(m_customPairCallback);
m_dynamicsWorld->addRigidBody(m_character->getRigidBody());
m_character->registerPairCache (m_customPairCallback->getOverlappingPairCache());
clientResetScene();
setCameraDistance(26.f);
@@ -391,7 +502,7 @@ void CharacterDemo::clientMoveAndDisplay()
if (m_character)
{
m_character->preStep (m_dynamicsWorld);
m_character->playerStep (dt, gForward, gBackward, gLeft, gRight);
m_character->playerStep (m_dynamicsWorld, dt, gForward, gBackward, gLeft, gRight);
if (gJump)
{
gJump = 0;
@@ -616,8 +727,8 @@ void CharacterDemo::updateCamera()
//update OpenGL camera settings
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(m_cameraPosition[0],m_cameraPosition[1],m_cameraPosition[2],
m_cameraTargetPosition[0],m_cameraTargetPosition[1], m_cameraTargetPosition[2],

View File

@@ -16,6 +16,7 @@ subject to the following restrictions:
#define CHARACTER_DEMO_H
class CharacterController;
class KinematicCharacterController;
class btCollisionShape;
@@ -27,7 +28,11 @@ class CharacterDemo : public DemoApplication
{
public:
#ifdef DYNAMIC_CHARACTER_CONTROLLER
CharacterController* m_character;
#else
KinematicCharacterController* m_character;
#endif
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;

View File

@@ -2,9 +2,9 @@
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
#include "LinearMath/btDefaultMotionState.h"
#include "CharacterController.h"
#include "DynamicCharacterController.h"
CharacterController::CharacterController ()
DynamicCharacterController::DynamicCharacterController ()
{
m_rayLambda[0] = 1.0;
m_rayLambda[1] = 1.0;
@@ -17,11 +17,11 @@ CharacterController::CharacterController ()
m_rigidBody = NULL;
}
CharacterController::~CharacterController ()
DynamicCharacterController::~DynamicCharacterController ()
{
}
void CharacterController::setup (btDynamicsWorld* dynamicsWorld, btScalar height, btScalar width)
void DynamicCharacterController::setup (btDynamicsWorld* dynamicsWorld, btScalar height, btScalar width, btScalar stepHeight)
{
btVector3 spherePositions[2];
btScalar sphereRadii[2];
@@ -48,7 +48,7 @@ void CharacterController::setup (btDynamicsWorld* dynamicsWorld, btScalar height
dynamicsWorld->addRigidBody (m_rigidBody);
}
void CharacterController::destroy (btDynamicsWorld* dynamicsWorld)
void DynamicCharacterController::destroy (btDynamicsWorld* dynamicsWorld)
{
if (m_shape)
{
@@ -62,12 +62,12 @@ void CharacterController::destroy (btDynamicsWorld* dynamicsWorld)
}
}
btRigidBody* CharacterController::getRigidBody ()
btRigidBody* DynamicCharacterController::getRigidBody ()
{
return m_rigidBody;
}
void CharacterController::preStep (btDynamicsWorld* dynamicsWorld)
void DynamicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
{
btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform);
@@ -118,7 +118,7 @@ void CharacterController::preStep (btDynamicsWorld* dynamicsWorld)
}
}
void CharacterController::playerStep (btScalar dt,
void DynamicCharacterController::playerStep (btScalar dt,
int forward,
int backward,
int left,
@@ -167,12 +167,12 @@ void CharacterController::playerStep (btScalar dt,
m_rigidBody->setCenterOfMassTransform (xform);
}
bool CharacterController::canJump () const
bool DynamicCharacterController::canJump () const
{
return onGround();
}
void CharacterController::jump ()
void DynamicCharacterController::jump ()
{
if (!canJump())
return;
@@ -185,7 +185,7 @@ void CharacterController::jump ()
m_rigidBody->applyCentralImpulse (up * magnitude);
}
bool CharacterController::onGround () const
bool DynamicCharacterController::onGround () const
{
return m_rayLambda[0] < btScalar(1.0);
}

View File

@@ -3,11 +3,13 @@
#include "LinearMath/btVector3.h"
#include "CharacterControllerInterface.h"
class btCollisionShape;
class btRigidBody;
class btDynamicsWorld;
class CharacterController
class DynamicCharacterController : public CharacterControllerInterface
{
protected:
btScalar m_halfHeight;
@@ -25,9 +27,9 @@ protected:
btScalar m_walkVelocity;
btScalar m_turnVelocity;
public:
CharacterController ();
~CharacterController ();
void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25);
DynamicCharacterController ();
~DynamicCharacterController ();
void setup (btDynamicsWorld* dynamicsWorld, btScalar height = 2.0, btScalar width = 0.25, btScalar stepHeight = 0.25);
void destroy (btDynamicsWorld* dynamicsWorld);
btRigidBody* getRigidBody ();

View File

@@ -0,0 +1,384 @@
#include <stdio.h>
#include "GLDebugDrawer.h"
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletDynamics/Dynamics/btRigidBody.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
#include "LinearMath/btDefaultMotionState.h"
#include "KinematicCharacterController.h"
/* TODO:
* Handle projecting/slide along surfaces
* Deal with starting in penetration
* Interact with dynamic objects
* Ride kinematicly animated platforms properly
* Step climbing
*/
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{
public:
ClosestNotMeRayResultCallback (btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
{
m_me = me;
}
virtual btScalar AddSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
{
if (rayResult.m_collisionObject == m_me)
return 1.0;
return ClosestRayResultCallback::AddSingleResult (rayResult, normalInWorldSpace);
}
protected:
btRigidBody* m_me;
};
class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
{
public:
ClosestNotMeConvexResultCallback (btRigidBody* me) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
{
m_me = me;
}
virtual btScalar AddSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
{
if (convexResult.m_hitCollisionObject == m_me)
return 1.0;
return ClosestConvexResultCallback::AddSingleResult (convexResult, normalInWorldSpace);
}
protected:
btRigidBody* m_me;
};
/*
* Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
*
* from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
*/
btVector3 computeReflectionDirection (const btVector3& direction, const btVector3& normal)
{
return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
}
/*
* Returns the portion of 'direction' that is parallel to 'normal'
*/
btVector3 parallelComponent (const btVector3& direction, const btVector3& normal)
{
btScalar magnitude = direction.dot(normal);
return normal * magnitude;
}
/*
* Returns the portion of 'direction' that is perpindicular to 'normal'
*/
btVector3 perpindicularComponent (const btVector3& direction, const btVector3& normal)
{
return direction - parallelComponent(direction, normal);
}
KinematicCharacterController::KinematicCharacterController ()
{
m_turnAngle = btScalar(0.0);
m_walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
m_shape = NULL;
m_pairCache = NULL;
m_rigidBody = NULL;
}
KinematicCharacterController::~KinematicCharacterController ()
{
}
void KinematicCharacterController::setup (btDynamicsWorld* dynamicsWorld, btScalar height, btScalar width, btScalar stepHeight)
{
btVector3 spherePositions[2];
btScalar sphereRadii[2];
sphereRadii[0] = width;
sphereRadii[1] = width;
spherePositions[0] = btVector3 (0.0, (height/btScalar(2.0) - width), 0.0);
spherePositions[1] = btVector3 (0.0, (-height/btScalar(2.0) + width), 0.0);
m_halfHeight = height/btScalar(2.0);
m_shape = new btMultiSphereShape (btVector3(width/btScalar(2.0), height/btScalar(2.0), width/btScalar(2.0)), &spherePositions[0], &sphereRadii[0], 2);
m_stepHeight = stepHeight;
m_height = height;
m_width = width;
btTransform startTransform;
startTransform.setIdentity ();
startTransform.setOrigin (btVector3(0.0, 4.0, 0.0));
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
m_rigidBody = new btRigidBody(cInfo);
m_rigidBody->setCollisionFlags( m_rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
m_rigidBody->setSleepingThresholds (0.0, 0.0);
m_rigidBody->setAngularFactor (0.0);
dynamicsWorld->addRigidBody (m_rigidBody);
}
void KinematicCharacterController::destroy (btDynamicsWorld* dynamicsWorld)
{
if (m_rigidBody)
{
dynamicsWorld->removeRigidBody (m_rigidBody);
delete m_rigidBody;
}
if (m_shape)
{
delete m_shape;
}
}
btRigidBody* KinematicCharacterController::getRigidBody ()
{
return m_rigidBody;
}
void KinematicCharacterController::recoverFromPenetration (btDynamicsWorld* dynamicsWorld)
{
if (m_pairCache == NULL)
return;
printf("%d\n", m_pairCache->getNumOverlappingPairs());
dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs (m_pairCache, dynamicsWorld->getDispatchInfo(), dynamicsWorld->getDispatcher());
btManifoldArray manifoldArray;
for (int i = 0; i < m_pairCache->getNumOverlappingPairs(); i++)
{
printf("%d\n",i);
manifoldArray.clear();
btBroadphasePair* collisionPair = &m_pairCache->getOverlappingPairArray()[i];
if (collisionPair->m_algorithm)
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
for (int j=0;j<manifoldArray.size();j++)
{
btPersistentManifold* manifold = manifoldArray[j];
for (int p=0;p<manifold->getNumContacts();p++)
{
const btManifoldPoint&pt = manifold->getContactPoint(p);
if (pt.getDistance() < 0.0)
{
printf("penetration %f\n", pt.getDistance());
} else {
printf("touching %f\n", pt.getDistance());
}
}
}
}
}
void KinematicCharacterController::stepUp (btDynamicsWorld* dynamicsWorld)
{
// phase 1: up
btTransform start, end;
m_targetPosition = m_currentPosition + btVector3 (btScalar(0.0), m_stepHeight, btScalar(0.0));
start.setIdentity ();
end.setIdentity ();
/* FIXME: Handle penetration properly */
start.setOrigin (m_currentPosition + btVector3(btScalar(0.0), btScalar(0.1), btScalar(0.0)));
end.setOrigin (m_targetPosition);
ClosestNotMeConvexResultCallback callback (m_rigidBody);
dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
if (callback.HasHit())
{
// we moved up only a fraction of the step height
m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
} else {
m_currentStepOffset = m_stepHeight;
m_currentPosition = m_targetPosition;
}
}
void KinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
{
btVector3 movementDirection = m_targetPosition - m_currentPosition;
btScalar movementLength = movementDirection.length();
movementDirection.normalize();
btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
reflectDir.normalize();
btVector3 parallelDir, perpindicularDir;
parallelDir = parallelComponent (reflectDir, hitNormal);
perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
m_targetPosition = m_currentPosition;
if (tangentMag != 0.0)
{
m_targetPosition += parallelDir * btScalar (tangentMag*movementLength);
}
if (normalMag != 0.0)
{
m_targetPosition += perpindicularDir * btScalar (normalMag*movementLength);
}
}
void KinematicCharacterController::stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove)
{
// phase 2: forward and strafe
btTransform start, end;
m_targetPosition = m_currentPosition + walkMove;
start.setIdentity ();
end.setIdentity ();
btScalar fraction = 1.0;
btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
while (fraction > btScalar(0.01))
{
start.setOrigin (m_currentPosition);
end.setOrigin (m_targetPosition);
ClosestNotMeConvexResultCallback callback (m_rigidBody);
dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
fraction -= callback.m_closestHitFraction;
if (callback.HasHit())
{
// we moved only a fraction
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
distance2 = (m_currentPosition-m_targetPosition).length2();
} else {
// we moved whole way
m_currentPosition = m_targetPosition;
}
}
}
void KinematicCharacterController::stepDown (btDynamicsWorld* dynamicsWorld, btScalar dt)
{
btTransform start, end;
// phase 3: down
btVector3 step_drop = btVector3(btScalar(0.0), m_currentStepOffset, btScalar(0.0));
btVector3 gravity_drop = btVector3(btScalar(0.0), m_stepHeight, btScalar(0.0));
m_targetPosition -= (step_drop + gravity_drop);
start.setIdentity ();
end.setIdentity ();
start.setOrigin (m_currentPosition);
end.setOrigin (m_targetPosition);
ClosestNotMeConvexResultCallback callback (m_rigidBody);
dynamicsWorld->convexSweepTest (m_shape, start, end, callback);
if (callback.HasHit())
{
// we dropped a fraction of the height -> hit floor
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
} else {
// we dropped the full height
m_currentPosition = m_targetPosition;
}
}
void KinematicCharacterController::registerPairCache (btOverlappingPairCache* pairCache)
{
m_pairCache = pairCache;
}
void KinematicCharacterController::preStep (btDynamicsWorld* dynamicsWorld)
{
btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform);
btVector3 forwardDir = xform.getBasis()[2];
btVector3 upDir = xform.getBasis()[1];
btVector3 strafeDir = xform.getBasis()[0];
forwardDir.normalize ();
upDir.normalize ();
strafeDir.normalize ();
m_upDirection = upDir;
m_forwardDirection = forwardDir;
m_strafeDirection = strafeDir;
m_currentPosition = xform.getOrigin();
m_targetPosition = m_currentPosition;
recoverFromPenetration (dynamicsWorld);
}
void KinematicCharacterController::playerStep (btDynamicsWorld* dynamicsWorld,
btScalar dt,
int forward,
int backward,
int left,
int right)
{
btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
btScalar walkSpeed = m_walkVelocity * dt;
if (left)
walkDirection += m_strafeDirection;
if (right)
walkDirection -= m_strafeDirection;
if (forward)
walkDirection += m_forwardDirection;
if (backward)
walkDirection -= m_forwardDirection;
btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform);
stepUp (dynamicsWorld);
stepForwardAndStrafe (dynamicsWorld, walkDirection * walkSpeed);
stepDown (dynamicsWorld, dt);
xform.setOrigin (m_currentPosition);
m_rigidBody->getMotionState()->setWorldTransform (xform);
m_rigidBody->setCenterOfMassTransform (xform);
}
bool KinematicCharacterController::canJump () const
{
return onGround();
}
void KinematicCharacterController::jump ()
{
if (!canJump())
return;
#if 0
currently no jumping.
btTransform xform;
m_rigidBody->getMotionState()->getWorldTransform (xform);
btVector3 up = xform.getBasis()[1];
up.normalize ();
btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
m_rigidBody->applyCentralImpulse (up * magnitude);
#endif
}
bool KinematicCharacterController::onGround () const
{
return true;
}

View File

@@ -0,0 +1,61 @@
#ifndef KINEMATIC_CHARACTER_CONTROLLER_H
#define KINEMATIC_CHARACTER_CONTROLLER_H
#include "LinearMath/btVector3.h"
#include "CharacterControllerInterface.h"
class btCollisionShape;
class btRigidBody;
class btDynamicsWorld;
class KinematicCharacterController : public CharacterControllerInterface
{
protected:
btScalar m_halfHeight;
btConvexShape* m_shape;
btRigidBody* m_rigidBody;
btOverlappingPairCache* m_pairCache;
btScalar m_turnAngle;
btScalar m_walkVelocity;
btScalar m_height;
btScalar m_width;
btScalar m_stepHeight;
btVector3 m_upDirection;
btVector3 m_forwardDirection;
btVector3 m_strafeDirection;
btVector3 m_currentPosition;
btScalar m_currentStepOffset;
btVector3 m_targetPosition;
void recoverFromPenetration (btDynamicsWorld* dynamicsWorld);
void stepUp (btDynamicsWorld* dynamicsWorld);
void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(1.0), btScalar normalMag = btScalar(0.0));
void stepForwardAndStrafe (btDynamicsWorld* dynamicsWorld, const btVector3& walkMove);
void stepDown (btDynamicsWorld* dynamicsWorld, btScalar dt);
public:
KinematicCharacterController ();
~KinematicCharacterController ();
void setup (btDynamicsWorld* dynamicsWorld, btScalar height = btScalar(1.75), btScalar width = btScalar(0.4), btScalar stepHeight = btScalar(0.35));
void destroy (btDynamicsWorld* dynamicsWorld);
btRigidBody* getRigidBody ();
void registerPairCache (btOverlappingPairCache* pairCache);
void preStep (btDynamicsWorld* dynamicsWorld);
void playerStep (btDynamicsWorld* dynamicsWorld, btScalar dt,
int forward,
int backward,
int left,
int right);
bool canJump () const;
void jump ();
bool onGround () const;
};
#endif // KINEMATIC_CHARACTER_CONTROLLER_H