At first, I have only vector, which is (direction * speed):

Then I move vector a bit up (imaginary slope). Basically character will try to climb slope, if there's slope is the way which is higher he'll just collide (y position += max slope * vector length), at this point I use convexSweepTest() to move character:

And finally, I move character down, I move down twice by same slope (first it compensating upslope I went, and 2nd is downslope, same slope but in different direction) and 3rd force is gravity, again, using convexSweepTest to move it:

I imagine it should happen about this way:

However, sometimes I fall through things (only straight downwards), I am quite unsure what's the problem. I ran over this post: http://bulletphysics.org/Bullet/phpBB3/ ... f=9&t=6336 and though it might be similar problem, so I lower hitFraction by a little. It fixed a lot of fall through, but it still happens. I though maybe someone knows what is wrong, here's my code:
Code: Select all
struct characterController : public btActionInterface{
struct ClosestCallback : public btCollisionWorld::ClosestConvexResultCallback{
ClosestCallback() : ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)){
}
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace){
return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
}
};
btPairCachingGhostObject* ghostObject;
btConvexShape* characterCollisionStanding;
btConvexShape* characterCollisionCrouching;
btVector3 velocityCharacter, velocityGravity;
bool onGround;
float maxSlope;
characterController(btVector3 &position){
onGround = false;
maxSlope = sin(PI / 5.0f);
characterCollisionStanding = new btCapsuleShape(0.3f, 1.2f);
characterCollisionCrouching = new btCapsuleShape(0.3f, 0.6f);
ghostObject = new btPairCachingGhostObject();
btTransform transform;
transform.setIdentity();
transform.setOrigin(position);
ghostObject->setWorldTransform(transform);
ghostObject->setCollisionShape(characterCollisionStanding);
physics->addAction(this);
physics->addCollisionObject(ghostObject, btBroadphaseProxy::SensorTrigger, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::SensorTrigger);
velocityCharacter = velocityGravity = btVector3(0, 0, 0);
}
virtual ~characterController(){
physics->removeAction(this);
physics->removeCollisionObject(ghostObject);
SAFE_DELETE(ghostObject);
SAFE_DELETE(characterCollisionStanding);
SAFE_DELETE(characterCollisionCrouching);
}
void SetStanding(){
if(ghostObject->getCollisionShape() == characterCollisionCrouching){
btTransform transform = ghostObject->getWorldTransform();
transform.setOrigin(transform.getOrigin() + btVector3(0, 0.3f, 0));
ClosestCallback callback;
ghostObject->convexSweepTest(characterCollisionStanding, transform, transform, callback);
if(!callback.hasHit()){
ghostObject->setWorldTransform(transform);
ghostObject->setCollisionShape(characterCollisionStanding);
}
}
}
void SetCrouching(){
if(ghostObject->getCollisionShape() == characterCollisionStanding){
btTransform transform = ghostObject->getWorldTransform();
transform.setOrigin(transform.getOrigin() - btVector3(0, 0.3f, 0));
ghostObject->setWorldTransform(transform);
ghostObject->setCollisionShape(characterCollisionCrouching);
}
}
void SetVelocity(btVector3 &vel){
velocityCharacter = vel;
}
virtual void updateAction(btCollisionWorld* world, btScalar deltaTimeStep){
stepLinear(deltaTimeStep);
stepDown(deltaTimeStep);
}
void stepLinear(btScalar deltaTimeStep){
btVector3 verticalMovement = btVector3(0, velocityCharacter.length() * maxSlope, 0) * deltaTimeStep;
btVector3 attemptMovement = velocityCharacter * deltaTimeStep + verticalMovement;
btTransform transformOld = ghostObject->getWorldTransform();
btTransform transformNew = transformOld;
transformNew.setOrigin(transformNew.getOrigin() + attemptMovement);
ClosestCallback callback;
ghostObject->convexSweepTest((btConvexShape*)ghostObject->getCollisionShape(), transformOld, transformNew, callback);
btVector3 orig = ghostObject->getWorldTransform().getOrigin();
btVector3 movement = attemptMovement * (callback.m_closestHitFraction - 0.01f);
ghostObject->getWorldTransform().setOrigin(orig + movement);
onGround = false;
}
void stepDown(btScalar deltaTimeStep){
velocityGravity += physics->getGravity() * deltaTimeStep * deltaTimeStep * 10.0f;
btVector3 verticalMovement = btVector3(0, velocityCharacter.length() * -maxSlope * 2, 0) * deltaTimeStep;
btVector3 attemptMovement = btVector3(0, -maxSlope, 0) * deltaTimeStep + velocityGravity + verticalMovement;
btTransform transformOld = ghostObject->getWorldTransform();
btTransform transformNew = transformOld;
transformNew.setOrigin(transformNew.getOrigin() + attemptMovement);
ClosestCallback callback;
ghostObject->convexSweepTest((btConvexShape*)ghostObject->getCollisionShape(), transformOld, transformNew, callback);
btVector3 orig = ghostObject->getWorldTransform().getOrigin();
btVector3 movement = attemptMovement * (callback.m_closestHitFraction - 0.01f);
ghostObject->getWorldTransform().setOrigin(orig + movement);
if(callback.hasHit()){
if(attemptMovement.y() < 0.0f)
onGround = true;
velocityGravity = btVector3(0, 0, 0);
}
}
void Jump(float power){
if(velocityGravity.y() <= 0 && onGround){
velocityGravity += btVector3(0, power, 0);
onGround = false;
}
}
void SetPlayerPosition(btVector3 &pos){
if(ghostObject->getCollisionShape() == characterCollisionStanding){
ghostObject->getWorldTransform().setOrigin(pos + btVector3(0, 0.6f, 0));
}
else if(ghostObject->getCollisionShape() == characterCollisionCrouching){
ghostObject->getWorldTransform().setOrigin(pos + btVector3(0, 0.3f, 0));
}
}
virtual void debugDraw(btIDebugDraw* debugDrawer){
}
};
Edit:
I seem to be able to fall through heightmaps, when I move at high speed along edge where heightmaps connect.
If I stand on flat surface of trimesh and jump (jump power 1.5f), falling causes me to go half through it, just fall through it, and in rare case it actually collides.