Bullet(Cocos2dx)之封裝PhysicsWorld3D
阿新 • • 發佈:2019-02-02
Bullet3之封裝PhysicsWorld3D
根據bullet3 HelloWorld程式去封裝一個PhysicsWorld3D,
首先應該去建立一個物理世界,而對於一個物理世界,預設都有重力,提供一個建立
世界的靜態方法(重力預設為(0, -10, 0))
static PhysicsWorld3D* create(const btVector3& gravity = btVector3(0, -10, 0));
負責建立世界,同時對世界初始化
這裡建立一個btDiscreteDynamicsWorld
直接複製bullet3 HelloWorld對世界的初始化,並修改
_collisionConfiguration,_dispatcher, _solver, _overlappingPairCache, _drawer均為成員變數,
具體使用參照Bullet的文件
PhysicsWorld3D* PhysicsWorld3D::create(const btVector3& gravity) { auto world = new PhysicsWorld3D; if (world && world->initWorld(gravity)) { return world; } delete world; return nullptr; } bool PhysicsWorld3D::initWorld(const btVector3& gravity) { _collisionConfiguration = new btDefaultCollisionConfiguration(); _dispatcher = new btCollisionDispatcher(_collisionConfiguration); _overlappingPairCache = new btDbvtBroadphase(); _solver = new btSequentialImpulseConstraintSolver; _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration); if (_world == nullptr) { return false; } _world->setGravity(gravity); return true; }
銷燬一個物理世界
void PhysicsWorld3D::destroy() { this->clear(); delete _collisionConfiguration; delete _dispatcher; delete _solver; delete _overlappingPairCache; delete _world; delete this; } void PhysicsWorld3D::clear() { int i; //remove the rigidbodies from the dynamics world and delete them for (i = _world->getNumCollisionObjects() - 1; i >= 0; i--) { btCollisionObject* obj = _world->getCollisionObjectArray()[i]; btRigidBody* body = btRigidBody::upcast(obj); if (body && body->getMotionState()) { delete body->getMotionState(); delete body->getCollisionShape(); } _world->removeCollisionObject(body); delete obj; } }
建立一些簡單的body
由於每種body都有自己的材質資訊
btRigidBodyConstructionInfo是構造一個剛體資訊的結構體,
我們只需關心幾個引數,
friction; // 摩擦係數
rollingFriction; // 滾動摩擦係數
restitution; // 恢復係數(彈性係數)
mass; // 質量
自己去實現一個簡單的材質結構體
struct PhysicsMaterial3D
{
btScalar friction;
btScalar rollingFriction;
btScalar restitution;
btScalar mass;
PhysicsMaterial3D() :
friction(0.0f),
rollingFriction(0.f),
restitution(0.f),
mass(0.f)
{}
PhysicsMaterial3D(btScalar aMass, btScalar aFriction, btScalar aRestitution, btScalar aRollingFriction) :
friction(aFriction),
rollingFriction(aRollingFriction),
restitution(aRestitution),
mass(aMass)
{}
};
並提供一個預設的材質資訊
const PhysicsMaterial3D PHYSICS_MATERIAL3D_DEFAULT(1.f, 0.5f, 0.5f, 0.0f);
實現構造3個基本物體,如下宣告
btRigidBody* addPlane(const btVector3& normal, const btVector3& position, const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
btRigidBody* addSphere(btScalar radius, const btVector3& position, const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
btRigidBody* addBox(const btVector3& halfSize, const btVector3& position, const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
對於一個無限的平面,需要一個法向量決定Plane的朝向,同時position決定plane的位置,當然還有材質,但是mass必須為0
對於一個球體(Sphere)半徑,位置,材質
對於一個盒子(Box)尺寸, 位置,材質
btRigidBody* PhysicsWorld3D::addPlane(const btVector3& normal, const btVector3& position, const PhysicsMaterial3D& material)
{
CCAssert(material.mass == 0.f, "plane's mass must be 0."); // 特殊處理,保證mass為0
btCollisionShape* groundShape = new btStaticPlaneShape(normal, 0.f);
auto body = getBody(groundShape, position, material);
_world->addRigidBody(body);
return body;
}
btRigidBody* PhysicsWorld3D::addSphere(btScalar radius, const btVector3& position, const PhysicsMaterial3D& material)
{
btCollisionShape* colShape = new btSphereShape(radius);
auto body = getBody(colShape, position, material);
_world->addRigidBody(body);
return body;
}
btRigidBody* PhysicsWorld3D::addBox(const btVector3& size, const btVector3& position, const PhysicsMaterial3D& material)
{
btCollisionShape* colShape = new btBoxShape(size * 0.5f); // halfSize
auto body = getBody(colShape, position, material);
_world->addRigidBody(body);
return body;
}
構造一個剛體包含一些共同的步驟collisionShape, position, material
由於Plane,Sphere,Box collisionShape型別不同,所以單獨實現,
其他的公共步驟可以抽離出來
btRigidBody* getBody(btCollisionShape* colShape, const btVector3& position, const PhysicsMaterial3D& material);
仿照HelloWorld構造body的方法
btRigidBody* PhysicsWorld3D::getBody(btCollisionShape* colShape, const btVector3& position, const PhysicsMaterial3D& material)
{
/// Create Dynamic Objects
btTransform startTransform;
startTransform.setIdentity();
//rigidbody is dynamic if and only if mass is non zero, otherwise static
bool isDynamic = (material.mass != 0.f);
btVector3 localInertia(0,0,0);
if (isDynamic)
colShape->calculateLocalInertia(material.mass, localInertia); // 計算物體慣性
startTransform.setOrigin(position); // 設定物體位置
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(material.mass, myMotionState,colShape,localInertia);
// 使用自定義的材質
rbInfo.m_restitution = material.restitution;
rbInfo.m_friction = material.friction;
rbInfo.m_rollingFriction = material.rollingFriction;
// 建立body
btRigidBody* body = new btRigidBody(rbInfo);
return body;
}
不要忘了物理世界的更新
void PhysicsWorld3D::update(float dt)
{
_world->stepSimulation(dt);
}