Bullet(Cocos2dx)之封装PhysicsWorld3D

Bullet3之封装PhysicsWorld3D

根据bullet3HelloWorld程序去封装一个PhysicsWorld3D

首先应该去创建一个物理世界,而对于一个物理世界,认都有重力,提供一个创建

世界的静态方法(重力认为(0,-10,0)

static PhysicsWorld3D* create(const btVector3& gravity = btVector3(0,0));

负责创建世界,同时对世界初始化

这里创建一个btdiscreteDynamicsWorld

直接复制bullet3HelloWorld对世界的初始化,并修改

_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,_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.0f); 

实现构造3个基本物体,如下声明

btRigidBody* addplane(const btVector3& normal,const btVector3& position,const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
btRigidBody* addSphere(btScalar radius,const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);
btRigidBody* addBox(const btVector3& halfSize,const PhysicsMaterial3D& material = PHYSICS_MATERIAL3D_DEFAULT);

对于一个无限的平面,需要一个法向量决定Plane的朝向,同时position决定plane的位置,当然还有材质,但是mass必须为0

对于一个球体(Sphere)半径,位置,材质

对于一个盒子(Box)尺寸,位置,材质

btRigidBody* PhysicsWorld3D::addplane(const btVector3& normal,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 PhysicsMaterial3D& material)
{
	btCollisionShape* colShape = new btSphereShape(radius);
	auto body = getBody(colShape,material);

	_world->addRigidBody(body);

	return body;
}

btRigidBody* PhysicsWorld3D::addBox(const btVector3& size,const PhysicsMaterial3D& material)
{
	btCollisionShape* colShape = new btBoxShape(size * 0.5f); // halfSize
	auto body = getBody(colShape,material);

	_world->addRigidBody(body);

	return body;
}

构造一个刚体包含一些共同的步骤collisionShape,material

由于Plane,Sphere,BoxcollisionShape类型不同,所以单独实现,

其他的公共步骤可以抽离出来

btRigidBody* getBody(btCollisionShape* colShape,const PhysicsMaterial3D& material);

仿照HelloWorld构造body的方法

btRigidBody* PhysicsWorld3D::getBody(btCollisionShape* colShape,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);
	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);
}

完整源码

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...