I've been trying to implement a jumping system into a character controller, and now I've implemented a simple solution and I want to share it with you guys.
My implementation uses the results previously gotten in the stepDown() method, i've changed this method just a little bit,
In my tests it seems to work just right.
The logic behind is simple, if the convex sweep test in the stepDown method hit anything I assume that the character isn't in the air, otherwise I set it as being in middle air :
typedef btPairCachingGhostObject GhostObject;
typedef btCollisionWorld::ClosestRayResultCallback ClosestRayResultCallback;
typedef btCollisionWorld::ClosestConvexResultCallback ClosestConvexResultCallback;
class ClosestNotMeRayResultCallback : public ClosestRayResultCallback{
public:
ClosestNotMeRayResultCallback( btCollisionObject* me )
: ClosestRayResultCallback( btVector3( 0.0f, 0.0f, 0.0f ), btVector3( 0.0f, 0.0f, 0.0f ) ),
me( me ){}
virtual btScalar addSingleResult( btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace ){
if( rayResult.m_collisionObject == this->me ){
return 1.0f;
}
return ClosestRayResultCallback::addSingleResult( rayResult, normalInWorldSpace );
}
protected:
btCollisionObject* me;
}; //class ClosestNotMeRayResultCallback;
class ClosestNotMeConvexResultCallback : public ClosestConvexResultCallback{
public:
ClosestNotMeConvexResultCallback( btCollisionObject* me )
: ClosestConvexResultCallback( btVector3( 0.0f, 0.0f, 0.0f ), btVector3( 0.0f, 0.0f, 0.0f ) ),
me( me ){}
virtual btScalar addSingleResult( btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace ){
if( convexResult.m_hitCollisionObject == this->me ){
return 1.0f;
}
return ClosestConvexResultCallback::addSingleResult( convexResult, normalInWorldSpace );
}
protected:
btCollisionObject* me;
}; //class ClosestNotMeConvexResultCallback;
class CharacterController : public btKinematicCharacterController{
public:
CharacterController( GhostObject* ghostObject, btConvexShape* convexShape, const float& stepHeight )
: btKinematicCharacterController( ghostObject, convexShape, stepHeight ),
gravity( -10.0f ), isOnGround( true )
{
this->setJumpSpeed( 5.0f );
this->setFallSpeed( 0.0f );
}
virtual void updateAction( btCollisionWorld* collisionWorld, btScalar diffTime ){
this->preStep( collisionWorld );
this->playerStep( collisionWorld, diffTime );
}
void playerStep( btCollisionWorld* collisionWorld, btScalar diffTime ){
if( !this->m_useWalkDirection && this->m_velocityTimeInterval <= 0.0f ){
return;
}
btTransform xform;
xform = this->m_ghostObject->getWorldTransform ();
this->stepUp( collisionWorld );
if( this->m_useWalkDirection ){
this->stepForwardAndStrafe( collisionWorld, this->m_walkDirection );
}else{
btScalar dtMoving =
( diffTime < this->m_velocityTimeInterval ) ? diffTime : this->m_velocityTimeInterval;
this->m_velocityTimeInterval -= diffTime;
btVector3 move = this->m_walkDirection*dtMoving;
this->stepForwardAndStrafe( collisionWorld, move );
}
this->stepDown( collisionWorld, diffTime );
xform.setOrigin( this->m_currentPosition );
this->m_ghostObject->setWorldTransform( xform );
}
void stepDown( btCollisionWorld* world, btScalar diffTime ){
btVector3 upAxis = this->getUpAxisDirections()[ this->m_upAxis ];
this->m_targetPosition -= upAxis*( this->m_currentStepOffset - this->m_fallSpeed*diffTime );
btTransform start, end;
start.setIdentity();
end.setIdentity();
start.setOrigin( this->m_currentPosition );
end.setOrigin( this->m_targetPosition );
ClosestNotMeConvexResultCallback callback( this->m_ghostObject );
callback.m_collisionFilterGroup = this->m_ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
callback.m_collisionFilterMask = this->m_ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
if( this->m_useGhostObjectSweepTest ){
this->m_ghostObject->convexSweepTest( this->m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration );
}else{
world->convexSweepTest( this->m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration );
}
if( callback.hasHit() ){
this->m_currentPosition.setInterpolate3( this->m_currentPosition, this->m_targetPosition, callback.m_closestHitFraction );
this->m_fallSpeed = 0.0f;
this->isOnGround = true;
}else{
this->m_currentPosition = this->m_targetPosition;
this->isOnGround = false;
}
this->m_fallSpeed += this->gravity*diffTime;
}
void jump(){
if( !this->canJump() ){
return;
}
this->m_fallSpeed = this->m_jumpSpeed;
}
bool onGround() const{
return this->isOnGround;
}
virtual ~CharacterController(){}
protected:
float gravity;
bool isOnGround;
}; //class CharacterController;
Opinions and tips please...
Hope it helps...
Simple implementation of Controller's jump() method
-
aymar
- Posts: 1
- Joined: Wed Jun 02, 2010 6:27 pm
-
LEgregius
- Posts: 26
- Joined: Tue Oct 14, 2008 1:34 am
Re: Simple implementation of Controller's jump() method
Look at issue 198 in the bug tracker. There is an updated character controller in there with lots of bugs fixed and jump support added. Try that one out and see if it does what you want. If you have some better code for that, great.