Cocos2d中提供了2种物理引擎,分别为Box2d和chipmunk,Box2d是C++实现的,Chipmunk是C实现的,因为Box2d是面向对象的,所以一般使用Box2d的比较多,另外Chipmunk也有Objective-c版的。
Box2d物理引擎比较复杂,本次只写简单的物理世界、静态及动态钢体的创建。
Box2D中的一些概念:
- 刚体:物体中的一种,和我们在物理中学习的刚体的概念是一样的,物体上2个间之间的距离都是完全不会变化的。不会发生变形。他就是Box2D中的body。刚体有3种:动态刚体,静态和棱柱钢体。
形状:一个依附于body的几何结构体,同时具有物理的摩擦(friction)和恢复(restitution)的材料性质。
- 约束:就是我们所熟悉的自由度(横纵坐标2个方向及自身的旋转)
- 世界:Box2d的容器,里面包括物体及他们之间的相互作用
创建一个物理世界:
//定义重力参数,纵向的重力加速度为-10.0f b2Vec2 gravity; gravity.Set(0.0f, -10.0f / 6.0f); //模拟月球的重力 _world = new b2World(gravity); //创建世界对象 _world->SetAllowSleeping(true); //允许休眠 _world->SetContinuousPhysics(true); //设置检测连续碰撞
创建一个静态的地形钢体,防止动态和棱柱钢体掉出屏幕之外:
//定义地形钢体描述并设置坐标为左下角 b2BodyDef groundBodyDef; groundBodyDef.position.Set(0, 0); //根据钢体的描述创建钢体对象 b2Body* groundBody = _world->CreateBody(&groundBodyDef); groundBody->SetType(b2_staticBody); b2EdgeShape groundBox; //定义地面盒形状 //2个点确定一条线,以下分别设置了屏幕的4个边 // bottom groundBox.Set(b2Vec2(0, 0), b2Vec2(_ScreenSize.width/PTM_RATIO, 0)); groundBody->CreateFixture(&groundBox,0); // top groundBox.Set(b2Vec2(0 ,_ScreenSize.height/PTM_RATIO), b2Vec2(_ScreenSize.width/PTM_RATIO,_ScreenSize.height/PTM_RATIO)); groundBody->CreateFixture(&groundBox,0); // left groundBox.Set(b2Vec2(0, _ScreenSize.height/PTM_RATIO), b2Vec2(0 ,0)); groundBody->CreateFixture(&groundBox,0); // right groundBox.Set(b2Vec2(_ScreenSize.width/PTM_RATIO, _ScreenSize.height/PTM_RATIO), b2Vec2(_ScreenSize.width/PTM_RATIO, 0)); groundBody->CreateFixture(&groundBox,0);
创建一个动态刚体(篮球):
//定义一个动态钢体 b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(_ScreenSize.width * 0.5 / PTM_RATIO, _ScreenSize.height * 0.5 / PTM_RATIO); b2Body *ballbody = _world->CreateBody(&bodyDef); ballbody->SetUserData(this->getBall()); ballbody->SetActive(true); //给这个动态钢体创建盒子形状 b2PolygonShape dynamicBox; dynamicBox.SetAsBox(.5f, .5f); //为该钢体定义夹具 b2FixtureDef fixtureDef; fixtureDef.shape = &dynamicBox; //绑定物体的形状 fixtureDef.density = 10.0f; //密度 fixtureDef.restitution = 0.9f; //弹性系数 fixtureDef.friction = 0.3f; //摩擦力 //在刚体的夹具工厂中创建夹具 ballbody->CreateFixture(&fixtureDef);
钢体的状态更新需要在定时器中完成:
void HelloWorld::update(float dt) { int velocityIterations = 8; int positionIterations = 1; //时间定义成固定的,如果用dt的话,会随着帧率的变化而变化 _world->Step(0.2f, velocityIterations, positionIterations); //枚举世界中的所有物体,找出有userdata的物体,强制转化为精灵 for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) { if (b->GetUserData() != NULL) { CCSprite *sprite = (CCSprite *)b->GetUserData(); if (sprite != NULL) { //获取物体的坐标并转换成cocos2d的坐标 b2Vec2 bodyPos = b->GetPosition(); CCPoint pos = ccp(bodyPos.x * PTM_RATIO, bodyPos.y * PTM_RATIO); float32 rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()); //转换角度 sprite->setPosition(pos); //设置精灵坐标 sprite->setRotation(rotation); //设置精灵角度 } } } }
完整代码下载地址:http://vdisk.weibo.com/s/EiAqz