mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-30 22:07:58 +03:00
Imported Upstream version 0.26.0
This commit is contained in:
commit
9a2b6c69b6
1398 changed files with 212217 additions and 0 deletions
643
libs/openengine/bullet/btKinematicCharacterController.cpp
Normal file
643
libs/openengine/bullet/btKinematicCharacterController.cpp
Normal file
|
@ -0,0 +1,643 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
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.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
||||
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
|
||||
#include "LinearMath/btDefaultMotionState.h"
|
||||
#include "btKinematicCharacterController.h"
|
||||
|
||||
///@todo Interact with dynamic objects,
|
||||
///Ride kinematicly animated platforms properly
|
||||
///Support ducking
|
||||
class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
||||
{
|
||||
public:
|
||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
||||
{
|
||||
m_me[0] = me;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me[], int count_) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
|
||||
{
|
||||
count = count_;
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
m_me[i] = me[i];
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
if (rayResult.m_collisionObject == m_me[i])
|
||||
return 1.0;
|
||||
|
||||
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
||||
}
|
||||
protected:
|
||||
btCollisionObject* m_me[10];
|
||||
int count;
|
||||
};
|
||||
|
||||
class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
|
||||
{
|
||||
public:
|
||||
btKinematicClosestNotMeConvexResultCallback( btCollisionObject* me, const btVector3& up, btScalar minSlopeDot )
|
||||
: btCollisionWorld::ClosestConvexResultCallback( btVector3( 0.0, 0.0, 0.0 ), btVector3( 0.0, 0.0, 0.0 ) ),
|
||||
m_me( me ), m_up( up ), m_minSlopeDot( minSlopeDot )
|
||||
{
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
|
||||
{
|
||||
if( convexResult.m_hitCollisionObject == m_me )
|
||||
return btScalar( 1 );
|
||||
|
||||
btVector3 hitNormalWorld;
|
||||
if( normalInWorldSpace )
|
||||
{
|
||||
hitNormalWorld = convexResult.m_hitNormalLocal;
|
||||
}
|
||||
else
|
||||
{
|
||||
///need to transform normal into worldspace
|
||||
hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
|
||||
}
|
||||
|
||||
// NOTE : m_hitNormalLocal is not always vertical on the ground with a capsule or a box...
|
||||
|
||||
btScalar dotUp = m_up.dot(hitNormalWorld);
|
||||
if( dotUp < m_minSlopeDot )
|
||||
return btScalar( 1 );
|
||||
|
||||
return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
|
||||
}
|
||||
|
||||
protected:
|
||||
btCollisionObject* m_me;
|
||||
const btVector3 m_up;
|
||||
btScalar m_minSlopeDot;
|
||||
};
|
||||
|
||||
|
||||
|
||||
btKinematicCharacterController::btKinematicCharacterController( btPairCachingGhostObject* externalGhostObject_,
|
||||
btPairCachingGhostObject* internalGhostObject_,
|
||||
btScalar stepHeight,
|
||||
btScalar constantScale,
|
||||
btScalar gravity,
|
||||
btScalar fallVelocity,
|
||||
btScalar jumpVelocity,
|
||||
btScalar recoveringFactor )
|
||||
{
|
||||
m_upAxis = btKinematicCharacterController::Y_AXIS;
|
||||
|
||||
m_walkDirection.setValue( btScalar( 0 ), btScalar( 0 ), btScalar( 0 ) );
|
||||
|
||||
m_useGhostObjectSweepTest = true;
|
||||
|
||||
externalGhostObject = externalGhostObject_;
|
||||
internalGhostObject = internalGhostObject_;
|
||||
|
||||
m_recoveringFactor = recoveringFactor;
|
||||
|
||||
m_stepHeight = stepHeight;
|
||||
|
||||
m_useWalkDirection = true; // use walk direction by default, legacy behavior
|
||||
m_velocityTimeInterval = btScalar( 0 );
|
||||
m_verticalVelocity = btScalar( 0 );
|
||||
m_verticalOffset = btScalar( 0 );
|
||||
|
||||
m_gravity = constantScale * gravity;
|
||||
m_fallSpeed = constantScale * fallVelocity; // Terminal velocity of a sky diver in m/s.
|
||||
|
||||
m_jumpSpeed = constantScale * jumpVelocity; // ?
|
||||
m_wasJumping = false;
|
||||
|
||||
setMaxSlope( btRadians( 45.0 ) );
|
||||
|
||||
mCollision = true;
|
||||
}
|
||||
|
||||
|
||||
btKinematicCharacterController::~btKinematicCharacterController ()
|
||||
{
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setVerticalVelocity(float z)
|
||||
{
|
||||
m_verticalVelocity = z;
|
||||
}
|
||||
|
||||
bool btKinematicCharacterController::recoverFromPenetration( btCollisionWorld* collisionWorld )
|
||||
{
|
||||
bool penetration = false;
|
||||
|
||||
if(!mCollision) return penetration;
|
||||
|
||||
collisionWorld->getDispatcher()->dispatchAllCollisionPairs( internalGhostObject->getOverlappingPairCache(),
|
||||
collisionWorld->getDispatchInfo(),
|
||||
collisionWorld->getDispatcher() );
|
||||
|
||||
btVector3 currentPosition = internalGhostObject->getWorldTransform().getOrigin();
|
||||
|
||||
btScalar maxPen = btScalar( 0 );
|
||||
|
||||
for( int i = 0; i < internalGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++ )
|
||||
{
|
||||
m_manifoldArray.resize(0);
|
||||
|
||||
btBroadphasePair* collisionPair = &internalGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
|
||||
if( collisionPair->m_algorithm )
|
||||
collisionPair->m_algorithm->getAllContactManifolds( m_manifoldArray );
|
||||
|
||||
|
||||
for( int j = 0; j < m_manifoldArray.size(); j++ )
|
||||
{
|
||||
btPersistentManifold* manifold = m_manifoldArray[j];
|
||||
|
||||
btScalar directionSign = manifold->getBody0() == internalGhostObject ? btScalar( -1.0 ) : btScalar( 1.0 );
|
||||
|
||||
for( int p = 0; p < manifold->getNumContacts(); p++ )
|
||||
{
|
||||
const btManifoldPoint&pt = manifold->getContactPoint( p );
|
||||
if( (manifold->getBody1() == externalGhostObject && manifold->getBody0() == internalGhostObject)
|
||||
||(manifold->getBody0() == externalGhostObject && manifold->getBody1() == internalGhostObject) )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
btScalar dist = pt.getDistance();
|
||||
|
||||
if( dist < 0.0 )
|
||||
{
|
||||
if( dist < maxPen )
|
||||
maxPen = dist;
|
||||
|
||||
// NOTE : btScalar affects the stairs but the parkinson...
|
||||
// 0.0 , the capsule can break the walls...
|
||||
currentPosition += pt.m_normalWorldOnB * directionSign * dist * m_recoveringFactor;
|
||||
|
||||
penetration = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ???
|
||||
//manifold->clearManifold();
|
||||
}
|
||||
}
|
||||
|
||||
btTransform transform = internalGhostObject->getWorldTransform();
|
||||
|
||||
transform.setOrigin( currentPosition );
|
||||
|
||||
internalGhostObject->setWorldTransform( transform );
|
||||
externalGhostObject->setWorldTransform( transform );
|
||||
|
||||
return penetration;
|
||||
}
|
||||
|
||||
|
||||
btVector3 btKinematicCharacterController::stepUp( btCollisionWorld* world, const btVector3& currentPosition, btScalar& currentStepOffset )
|
||||
{
|
||||
btVector3 targetPosition = currentPosition + getUpAxisDirections()[ m_upAxis ] * ( m_stepHeight + ( m_verticalOffset > btScalar( 0.0 ) ? m_verticalOffset : 0.0 ) );
|
||||
|
||||
//if the no collisions mode is on, no need to go any further
|
||||
if(!mCollision)
|
||||
{
|
||||
currentStepOffset = m_stepHeight;
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
// Retrieve the collision shape
|
||||
//
|
||||
btCollisionShape* collisionShape = externalGhostObject->getCollisionShape();
|
||||
btAssert( collisionShape->isConvex() );
|
||||
|
||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
||||
|
||||
// FIXME: Handle penetration properly
|
||||
//
|
||||
btTransform start;
|
||||
start.setIdentity();
|
||||
start.setOrigin( currentPosition + getUpAxisDirections()[ m_upAxis ] * ( convexShape->getMargin() ) );
|
||||
|
||||
btTransform end;
|
||||
end.setIdentity();
|
||||
end.setOrigin( targetPosition );
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback( externalGhostObject, -getUpAxisDirections()[ m_upAxis ], m_maxSlopeCosine );
|
||||
callback.m_collisionFilterGroup = externalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = externalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
// Sweep test
|
||||
//
|
||||
if( m_useGhostObjectSweepTest )
|
||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
else
|
||||
world->convexSweepTest( convexShape, start, end, callback );
|
||||
|
||||
if( callback.hasHit() )
|
||||
{
|
||||
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
||||
//
|
||||
if( callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > btScalar( 0.0 ) )
|
||||
{
|
||||
// We moved up only a fraction of the step height
|
||||
//
|
||||
currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
|
||||
|
||||
return currentPosition.lerp( targetPosition, callback.m_closestHitFraction );
|
||||
}
|
||||
|
||||
m_verticalVelocity = btScalar( 0.0 );
|
||||
m_verticalOffset = btScalar( 0.0 );
|
||||
|
||||
return currentPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentStepOffset = m_stepHeight;
|
||||
return targetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///Reflect the vector d around the vector r
|
||||
inline btVector3 reflect( const btVector3& d, const btVector3& r )
|
||||
{
|
||||
return d - ( btScalar( 2.0 ) * d.dot( r ) ) * r;
|
||||
}
|
||||
|
||||
|
||||
///Project a vector u on another vector v
|
||||
inline btVector3 project( const btVector3& u, const btVector3& v )
|
||||
{
|
||||
return v * u.dot( v );
|
||||
}
|
||||
|
||||
|
||||
///Helper for computing the character sliding
|
||||
inline btVector3 slide( const btVector3& direction, const btVector3& planeNormal )
|
||||
{
|
||||
return direction - project( direction, planeNormal );
|
||||
}
|
||||
|
||||
|
||||
|
||||
btVector3 slideOnCollision( const btVector3& fromPosition, const btVector3& toPosition, const btVector3& hitNormal )
|
||||
{
|
||||
btVector3 moveDirection = toPosition - fromPosition;
|
||||
btScalar moveLength = moveDirection.length();
|
||||
|
||||
if( moveLength <= btScalar( SIMD_EPSILON ) )
|
||||
return toPosition;
|
||||
|
||||
moveDirection.normalize();
|
||||
|
||||
btVector3 reflectDir = reflect( moveDirection, hitNormal );
|
||||
reflectDir.normalize();
|
||||
|
||||
return fromPosition + slide( reflectDir, hitNormal ) * moveLength;
|
||||
}
|
||||
|
||||
|
||||
btVector3 btKinematicCharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& currentPosition, const btVector3& walkMove )
|
||||
{
|
||||
// We go to !
|
||||
//
|
||||
btVector3 targetPosition = currentPosition + walkMove;
|
||||
|
||||
//if the no collisions mode is on, no need to go any further
|
||||
if(!mCollision) return targetPosition;
|
||||
|
||||
// Retrieve the collision shape
|
||||
//
|
||||
btCollisionShape* collisionShape = externalGhostObject->getCollisionShape();
|
||||
btAssert( collisionShape->isConvex() );
|
||||
|
||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
||||
|
||||
btTransform start;
|
||||
start.setIdentity();
|
||||
|
||||
btTransform end;
|
||||
end.setIdentity();
|
||||
|
||||
btScalar fraction = btScalar( 1.0 );
|
||||
|
||||
// This optimization scheme suffers in the corners.
|
||||
// It basically jumps from a wall to another, then fails to find a new
|
||||
// position (after 4 iterations here) and finally don't move at all.
|
||||
//
|
||||
// The stepping algorithm adds some problems with stairs. It seems
|
||||
// the treads create some fake corner using capsules for collisions.
|
||||
//
|
||||
for( int i = 0; i < 4 && fraction > btScalar( 0.01 ); i++ )
|
||||
{
|
||||
start.setOrigin( currentPosition );
|
||||
end.setOrigin( targetPosition );
|
||||
|
||||
btVector3 sweepDirNegative = currentPosition - targetPosition;
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback( externalGhostObject, sweepDirNegative, btScalar( 0.0 ) );
|
||||
callback.m_collisionFilterGroup = externalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = externalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
if( m_useGhostObjectSweepTest )
|
||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
else
|
||||
collisionWorld->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
if( callback.hasHit() )
|
||||
{
|
||||
// Try another target position
|
||||
//
|
||||
targetPosition = slideOnCollision( currentPosition, targetPosition, callback.m_hitNormalWorld );
|
||||
fraction = callback.m_closestHitFraction;
|
||||
}
|
||||
else
|
||||
|
||||
// Move to the valid target position
|
||||
//
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
// Don't move if you can't find a valid target position...
|
||||
// It prevents some flickering.
|
||||
//
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
|
||||
///Handle the gravity
|
||||
btScalar btKinematicCharacterController::addFallOffset( bool wasOnGround, btScalar currentStepOffset, btScalar dt )
|
||||
{
|
||||
btScalar downVelocity = ( m_verticalVelocity < 0.0 ? -m_verticalVelocity : btScalar( 0.0 ) ) * dt;
|
||||
|
||||
if( downVelocity > btScalar( 0.0 ) && downVelocity < m_stepHeight && ( wasOnGround || !m_wasJumping ) )
|
||||
downVelocity = m_stepHeight;
|
||||
|
||||
return currentStepOffset + downVelocity;
|
||||
}
|
||||
|
||||
|
||||
btVector3 btKinematicCharacterController::stepDown( btCollisionWorld* collisionWorld, const btVector3& currentPosition, btScalar currentStepOffset )
|
||||
{
|
||||
btVector3 stepDrop = getUpAxisDirections()[ m_upAxis ] * currentStepOffset;
|
||||
|
||||
// Be sure we are falling from the last m_currentPosition
|
||||
// It prevents some flickering
|
||||
//
|
||||
btVector3 targetPosition = currentPosition - stepDrop;
|
||||
|
||||
//if the no collisions mode is on, no need to go any further
|
||||
if(!mCollision) return targetPosition;
|
||||
|
||||
btTransform start;
|
||||
start.setIdentity();
|
||||
start.setOrigin( currentPosition );
|
||||
|
||||
btTransform end;
|
||||
end.setIdentity();
|
||||
end.setOrigin( targetPosition );
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback( internalGhostObject, getUpAxisDirections()[ m_upAxis ], m_maxSlopeCosine );
|
||||
callback.m_collisionFilterGroup = internalGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = internalGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
// Retrieve the collision shape
|
||||
//
|
||||
btCollisionShape* collisionShape = internalGhostObject->getCollisionShape();
|
||||
btAssert( collisionShape->isConvex() );
|
||||
btConvexShape* convexShape = ( btConvexShape* )collisionShape;
|
||||
|
||||
if( m_useGhostObjectSweepTest )
|
||||
externalGhostObject->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
else
|
||||
collisionWorld->convexSweepTest( convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration );
|
||||
|
||||
if( callback.hasHit() )
|
||||
{
|
||||
m_verticalVelocity = btScalar( 0.0 );
|
||||
m_verticalOffset = btScalar( 0.0 );
|
||||
m_wasJumping = false;
|
||||
|
||||
// We dropped a fraction of the height -> hit floor
|
||||
//
|
||||
return currentPosition.lerp( targetPosition, callback.m_closestHitFraction );
|
||||
}
|
||||
else
|
||||
|
||||
// We dropped the full height
|
||||
//
|
||||
return targetPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void btKinematicCharacterController::setWalkDirection( const btVector3& walkDirection )
|
||||
{
|
||||
m_useWalkDirection = true;
|
||||
m_walkDirection = walkDirection;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setVelocityForTimeInterval( const btVector3& velocity, btScalar timeInterval )
|
||||
{
|
||||
m_useWalkDirection = false;
|
||||
m_walkDirection = velocity;
|
||||
m_velocityTimeInterval = timeInterval;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::reset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::warp( const btVector3& origin )
|
||||
{
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
transform.setOrigin( -origin );
|
||||
|
||||
externalGhostObject->setWorldTransform( transform );
|
||||
internalGhostObject->setWorldTransform( transform );
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::preStep( btCollisionWorld* collisionWorld )
|
||||
{
|
||||
BT_PROFILE( "preStep" );
|
||||
|
||||
for( int i = 0; i < 4 && recoverFromPenetration ( collisionWorld ); i++ );
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt )
|
||||
{
|
||||
BT_PROFILE( "playerStep" );
|
||||
|
||||
if( !m_useWalkDirection && m_velocityTimeInterval <= btScalar( 0.0 ) )
|
||||
return;
|
||||
|
||||
bool wasOnGround = onGround();
|
||||
|
||||
// Handle the gravity
|
||||
//
|
||||
m_verticalVelocity -= m_gravity * dt;
|
||||
|
||||
if( m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed )
|
||||
m_verticalVelocity = m_jumpSpeed;
|
||||
|
||||
if( m_verticalVelocity < 0.0 && btFabs( m_verticalVelocity ) > btFabs( m_fallSpeed ) )
|
||||
m_verticalVelocity = -btFabs( m_fallSpeed );
|
||||
|
||||
m_verticalOffset = m_verticalVelocity * dt;
|
||||
|
||||
// This forced stepping up can cause problems when the character
|
||||
// walks (jump in fact...) under too low ceilings.
|
||||
//
|
||||
btVector3 currentPosition = externalGhostObject->getWorldTransform().getOrigin();
|
||||
btScalar currentStepOffset;
|
||||
|
||||
currentPosition = stepUp( collisionWorld, currentPosition, currentStepOffset );
|
||||
|
||||
// Move in the air and slide against the walls ignoring the stair steps.
|
||||
//
|
||||
if( m_useWalkDirection )
|
||||
currentPosition = stepForwardAndStrafe( collisionWorld, currentPosition, m_walkDirection );
|
||||
|
||||
else
|
||||
{
|
||||
btScalar dtMoving = ( dt < m_velocityTimeInterval ) ? dt : m_velocityTimeInterval;
|
||||
m_velocityTimeInterval -= dt;
|
||||
|
||||
// How far will we move while we are moving ?
|
||||
//
|
||||
btVector3 moveDirection = m_walkDirection * dtMoving;
|
||||
|
||||
currentPosition = stepForwardAndStrafe( collisionWorld, currentPosition, moveDirection );
|
||||
}
|
||||
|
||||
// Finally find the ground.
|
||||
//
|
||||
currentStepOffset = addFallOffset( wasOnGround, currentStepOffset, dt );
|
||||
|
||||
currentPosition = stepDown( collisionWorld, currentPosition, currentStepOffset );
|
||||
|
||||
// Apply the new position to the collision objects.
|
||||
//
|
||||
btTransform tranform;
|
||||
tranform = externalGhostObject->getWorldTransform();
|
||||
tranform.setOrigin( currentPosition );
|
||||
|
||||
externalGhostObject->setWorldTransform( tranform );
|
||||
internalGhostObject->setWorldTransform( tranform );
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setFallSpeed( btScalar fallSpeed )
|
||||
{
|
||||
m_fallSpeed = fallSpeed;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setJumpSpeed( btScalar jumpSpeed )
|
||||
{
|
||||
m_jumpSpeed = jumpSpeed;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setMaxJumpHeight( btScalar maxJumpHeight )
|
||||
{
|
||||
m_maxJumpHeight = maxJumpHeight;
|
||||
}
|
||||
|
||||
|
||||
bool btKinematicCharacterController::canJump() const
|
||||
{
|
||||
return onGround();
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::jump()
|
||||
{
|
||||
if( !canJump() )
|
||||
return;
|
||||
|
||||
m_verticalVelocity = m_jumpSpeed;
|
||||
m_wasJumping = true;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setGravity( btScalar gravity )
|
||||
{
|
||||
m_gravity = gravity;
|
||||
}
|
||||
|
||||
|
||||
btScalar btKinematicCharacterController::getGravity() const
|
||||
{
|
||||
return m_gravity;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::setMaxSlope( btScalar slopeRadians )
|
||||
{
|
||||
m_maxSlopeRadians = slopeRadians;
|
||||
m_maxSlopeCosine = btCos( slopeRadians );
|
||||
}
|
||||
|
||||
|
||||
btScalar btKinematicCharacterController::getMaxSlope() const
|
||||
{
|
||||
return m_maxSlopeRadians;
|
||||
}
|
||||
|
||||
|
||||
bool btKinematicCharacterController::onGround() const
|
||||
{
|
||||
return btFabs( m_verticalVelocity ) < btScalar( SIMD_EPSILON ) &&
|
||||
btFabs( m_verticalOffset ) < btScalar( SIMD_EPSILON );
|
||||
}
|
||||
|
||||
|
||||
btVector3* btKinematicCharacterController::getUpAxisDirections()
|
||||
{
|
||||
static btVector3 sUpAxisDirection[] =
|
||||
{
|
||||
btVector3( btScalar( 0.0 ), btScalar( 0.0 ), btScalar( 0.0 ) ),
|
||||
btVector3( btScalar( 0.0 ), btScalar( 1.0 ), btScalar( 0.0 ) ),
|
||||
btVector3( btScalar( 0.0 ), btScalar( 0.0 ), btScalar( 1.0 ) )
|
||||
};
|
||||
|
||||
return sUpAxisDirection;
|
||||
}
|
||||
|
||||
|
||||
void btKinematicCharacterController::debugDraw( btIDebugDraw* debugDrawer )
|
||||
{
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue