mirror of
https://github.com/bulletphysics/bullet3
synced 2025-01-10 17:30:12 +00:00
205 lines
5.2 KiB
C++
205 lines
5.2 KiB
C++
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
|
#include "BulletDynamics/Dynamics/btRigidBody.h"
|
|
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
|
|
#include "LinearMath/btDefaultMotionState.h"
|
|
#include "DynamicCharacterController.h"
|
|
|
|
DynamicCharacterController::DynamicCharacterController ()
|
|
{
|
|
m_rayLambda[0] = 1.0;
|
|
m_rayLambda[1] = 1.0;
|
|
m_halfHeight = 1.0;
|
|
m_turnAngle = 0.0;
|
|
m_maxLinearVelocity = 10.0;
|
|
m_walkVelocity = 8.0; // meters/sec
|
|
m_turnVelocity = 1.0; // radians/sec
|
|
m_shape = NULL;
|
|
m_rigidBody = NULL;
|
|
}
|
|
|
|
DynamicCharacterController::~DynamicCharacterController ()
|
|
{
|
|
}
|
|
|
|
void DynamicCharacterController::setup (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 (&spherePositions[0], &sphereRadii[0], 2);
|
|
|
|
btTransform startTransform;
|
|
startTransform.setIdentity ();
|
|
startTransform.setOrigin (btVector3(0.0, 2.0, 0.0));
|
|
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
|
btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
|
|
m_rigidBody = new btRigidBody(cInfo);
|
|
// kinematic vs. static doesn't work
|
|
//m_rigidBody->setCollisionFlags( m_rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
|
|
m_rigidBody->setSleepingThresholds (0.0, 0.0);
|
|
m_rigidBody->setAngularFactor (0.0);
|
|
|
|
}
|
|
|
|
void DynamicCharacterController::destroy ()
|
|
{
|
|
if (m_shape)
|
|
{
|
|
delete m_shape;
|
|
}
|
|
|
|
if (m_rigidBody)
|
|
{
|
|
delete m_rigidBody;
|
|
m_rigidBody = 0;
|
|
}
|
|
}
|
|
|
|
btCollisionObject* DynamicCharacterController::getCollisionObject ()
|
|
{
|
|
return m_rigidBody;
|
|
}
|
|
|
|
void DynamicCharacterController::preStep (const btCollisionWorld* collisionWorld)
|
|
{
|
|
btTransform xform;
|
|
m_rigidBody->getMotionState()->getWorldTransform (xform);
|
|
btVector3 down = -xform.getBasis()[1];
|
|
btVector3 forward = xform.getBasis()[2];
|
|
down.normalize ();
|
|
forward.normalize();
|
|
|
|
m_raySource[0] = xform.getOrigin();
|
|
m_raySource[1] = xform.getOrigin();
|
|
|
|
m_rayTarget[0] = m_raySource[0] + down * m_halfHeight * btScalar(1.1);
|
|
m_rayTarget[1] = m_raySource[1] + forward * m_halfHeight * btScalar(1.1);
|
|
|
|
class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback
|
|
{
|
|
public:
|
|
ClosestNotMe (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;
|
|
};
|
|
|
|
ClosestNotMe rayCallback(m_rigidBody);
|
|
|
|
int i = 0;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
rayCallback.m_closestHitFraction = 1.0;
|
|
collisionWorld->rayTest (m_raySource[i], m_rayTarget[i], rayCallback);
|
|
if (rayCallback.hasHit())
|
|
{
|
|
m_rayLambda[i] = rayCallback.m_closestHitFraction;
|
|
} else {
|
|
m_rayLambda[i] = 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DynamicCharacterController::playerStep (const btCollisionWorld* dynaWorld,btScalar dt,
|
|
int forward,
|
|
int backward,
|
|
int left,
|
|
int right,
|
|
int jump)
|
|
{
|
|
btTransform xform;
|
|
m_rigidBody->getMotionState()->getWorldTransform (xform);
|
|
|
|
/* Handle turning */
|
|
if (left)
|
|
m_turnAngle -= dt * m_turnVelocity;
|
|
if (right)
|
|
m_turnAngle += dt * m_turnVelocity;
|
|
|
|
xform.setRotation (btQuaternion (btVector3(0.0, 1.0, 0.0), m_turnAngle));
|
|
|
|
btVector3 linearVelocity = m_rigidBody->getLinearVelocity();
|
|
btScalar speed = m_rigidBody->getLinearVelocity().length();
|
|
|
|
btVector3 forwardDir = xform.getBasis()[2];
|
|
forwardDir.normalize ();
|
|
btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
|
|
btScalar walkSpeed = m_walkVelocity * dt;
|
|
|
|
if (forward)
|
|
walkDirection += forwardDir;
|
|
if (backward)
|
|
walkDirection -= forwardDir;
|
|
|
|
|
|
|
|
if (!forward && !backward && onGround())
|
|
{
|
|
/* Dampen when on the ground and not being moved by the player */
|
|
linearVelocity *= btScalar(0.2);
|
|
m_rigidBody->setLinearVelocity (linearVelocity);
|
|
} else {
|
|
if (speed < m_maxLinearVelocity)
|
|
{
|
|
btVector3 velocity = linearVelocity + walkDirection * walkSpeed;
|
|
m_rigidBody->setLinearVelocity (velocity);
|
|
}
|
|
}
|
|
|
|
m_rigidBody->getMotionState()->setWorldTransform (xform);
|
|
m_rigidBody->setCenterOfMassTransform (xform);
|
|
}
|
|
|
|
bool DynamicCharacterController::canJump () const
|
|
{
|
|
return onGround();
|
|
}
|
|
|
|
void DynamicCharacterController::jump ()
|
|
{
|
|
if (!canJump())
|
|
return;
|
|
|
|
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);
|
|
}
|
|
|
|
bool DynamicCharacterController::onGround () const
|
|
{
|
|
return m_rayLambda[0] < btScalar(1.0);
|
|
}
|
|
|
|
void DynamicCharacterController::reset ()
|
|
{
|
|
}
|
|
void DynamicCharacterController::warp (const btVector3& origin)
|
|
{
|
|
}
|
|
void DynamicCharacterController::registerPairCacheAndDispatcher (btOverlappingPairCache* pairCache, btCollisionDispatcher* dispatcher)
|
|
{
|
|
|
|
}
|
|
|