Bullet(Cocos2dx)之封装PhysicsWorld3D

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);
}

完整源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cocos2d-x 是一个开源的跨平台游戏开发框架,支持 C++、Lua 和 JavaScript 等语言。以下是一个简单的飞机大战游戏的制作流程: 1. 创建一个新的 Cocos2d-x 项目,在命令行中使用以下命令: ``` cocos new MyGame -p com.your_company.mygame -l cpp -d /path/to/your/project ``` 其中,`MyGame` 是项目的名称,`com.your_company.mygame` 是项目的包名,`/path/to/your/project` 是项目的路径。 2. 在 `Classes` 文件夹下创建游戏场景类和游戏层类。游戏场景类负责管理游戏层,游戏层类负责绘制游戏界面和处理用户输入事件。可以参考以下代码: ```c++ class GameScene : public cocos2d::Scene { public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(GameScene); }; class GameLayer : public cocos2d::Layer { public: virtual bool init(); void update(float delta); CREATE_FUNC(GameLayer); }; ``` 3. 在游戏层中添加背景图和玩家飞机。可以使用 `Sprite` 类来加载图片资源,并使用 `addChild()` 方法将其添加到层中。例如: ```c++ auto background = Sprite::create("background.png"); background->setPosition(visibleSize.width / 2, visibleSize.height / 2); addChild(background); player = Sprite::create("player.png"); player->setPosition(visibleSize.width / 2, player->getContentSize().height / 2); addChild(player); ``` 4. 实现玩家飞机的移动和射击功能。可以使用 `EventKeyboard` 类来监听键盘事件,并在 `update()` 方法中更新玩家飞机的位置和子弹的位置。例如: ```c++ void GameLayer::update(float delta) { // 移动玩家飞机 if (isKeyPressed(EventKeyboard::KeyCode::KEY_UP_ARROW)) { player->setPositionY(player->getPositionY() + 5.0f); } if (isKeyPressed(EventKeyboard::KeyCode::KEY_DOWN_ARROW)) { player->setPositionY(player->getPositionY() - 5.0f); } if (isKeyPressed(EventKeyboard::KeyCode::KEY_LEFT_ARROW)) { player->setPositionX(player->getPositionX() - 5.0f); } if (isKeyPressed(EventKeyboard::KeyCode::KEY_RIGHT_ARROW)) { player->setPositionX(player->getPositionX() + 5.0f); } // 发射子弹 if (isKeyPressed(EventKeyboard::KeyCode::KEY_SPACE)) { auto bullet = Sprite::create("bullet.png"); bullet->setPosition(player->getPositionX(), player->getPositionY() + player->getContentSize().height / 2); addChild(bullet); auto moveBy = MoveBy::create(1.0f, Vec2(0, visibleSize.height)); auto removeSelf = RemoveSelf::create(); auto sequence = Sequence::create(moveBy, removeSelf, nullptr); bullet->runAction(sequence); } } ``` 5. 添加敌机和碰撞检测功能。可以使用定时器来定期生成敌机,并使用 `Rect` 类来判断玩家飞机和子弹是否与敌机发生碰撞。例如: ```c++ void GameLayer::addEnemy(float delta) { auto enemy = Sprite::create("enemy.png"); float x = CCRANDOM_0_1() * visibleSize.width; enemy->setPosition(x, visibleSize.height + enemy->getContentSize().height / 2); addChild(enemy); auto moveBy = MoveBy::create(2.0f, Vec2(0, -visibleSize.height - enemy->getContentSize().height)); auto removeSelf = RemoveSelf::create(); auto sequence = Sequence::create(moveBy, removeSelf, nullptr); enemy->runAction(sequence); } void GameLayer::checkCollision() { for (auto enemy : enemies) { if (player->getBoundingBox().intersectsRect(enemy->getBoundingBox())) { // 碰撞处理 } for (auto bullet : bullets) { if (bullet->getBoundingBox().intersectsRect(enemy->getBoundingBox())) { // 碰撞处理 } } } } ``` 6. 最后,在游戏场景类的 `init()` 方法中添加游戏层、定时器和碰撞检测函数。例如: ```c++ bool GameScene::init() { if (!Scene::init()) { return false; } auto gameLayer = GameLayer::create(); addChild(gameLayer); schedule(schedule_selector(GameLayer::addEnemy), 1.0f); scheduleUpdate(); return true; } void GameLayer::update(float delta) { checkCollision(); } ``` 以上是一个简单的飞机大战游戏的制作流程,具体的实现细节还需要结合实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值