定义重力,新建世界:
b2Vec2 gravity;
gravity.Set(0.0f,-10.0f);
world = new b2World(gravity);
允许刚体休眠和创建地面:
world->SetAllowSleeping(true);
world->SetContinuousPhysics(true);
静态刚体:没有质量,没有速度,只可以手动来改变它的位置。
棱柱刚体:没有质量,但是可以有速度,可以自己更新位置。
动态刚体:有质量,也有速度。
创建刚体步骤:
1)生成一个刚体定义
2)根据刚体定义生成刚体
通常在Box2D引擎中新建一个物体需要经历如下步骤:
1)使用位置和阻尼等参数定义物体
2)使用世界对象创建物体
3)使用几何结构、摩擦和密度等参数定义对象
4)调整物体质量和形状相匹配
定义物体:
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
创建物体:
b2Body* groundBody = world->CreateBody(&groundBodyDef);
定义物体边界:
b2EdgeShape groundBox;
groundBox.Set(b2Vec2(0,0),b2Vec2(s.width/PTM_RATIO,0));//bottom
groundBody->CreateFixture(&groundBox,0);
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO),b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));//top
groundBody->CreateFixture(&groundBox,0);
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO),s.height/PTM_RATIO,b2Vec2(0,0));//left
groundBody->CreateFixture(&groundBox,0);
groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO),b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
//先定义4条边,最后把他定义到物体中。四条边包围了一个“空心”的世界.setAsBox创建的世界是实心的。
//Box2D采用米、千克、秒作单位。把游戏中像素级的长度单位转换为米就要除以PTM_RATIO(0.1-10m范围较好,32pixel=1m)。
注:和物体定义一样,它只是把数据复制到物体中。这个形状的定义可以重新被利用,定义的形状
必须和物体绑定在一起,形状才有意义。
定义动态刚体:
void Box2DTestLayer::addNewSpriteAtPosition(CCPoint p){
CCLOG("Add sprite %0.2f x %02.f",p.x,p.y);
CCNode* parent = getChildByTag(kTagParentNode);
int idx = (CCRANDOM_0_1() > 0.5?0:1);
int idy = (CCRANDOM_0_1() > 0.5?0:1);
PhysicsSprite* sprite = new PhysicsSprite();
sprite->initWithTexture(m_pSpriteTexture,CCRectMake(32*idx,32*idy,32,32));
sprite->autorelease();
parent->addChild(sprite);
sprite->setPosition(CCPointMake(p.x,p.y));
b2BodyDef bodyDef; //刚体定义
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RADIO,p.y/PTM_RATIO);
b2Body* body = world->CreateBody(&bodyDef); //生成刚体
b2PolygonShap dynamicBox; //刚体形状
dynamicBox.SetAsBox(.5f,.5f);
b2FixtureDef fixtureDef; //刚体支架
fixtureDef.shap = & dynamicBox;
fixtureDef.density = 1.0f; //密度
fixtureDef.friction = 0.3f; //摩擦
body->CreateFixture(&fixtureDef);
sprite->setPhysicsBody(body);
}
声明物理精灵类:
class PhysicsSprite : public CCSprite{
public:
PhysicsSprite();
void setPhysicsBody(b2Body* body);
virtual bool isDirty(void);
virtual CCAFFineTransform nodeToParentTransform(void);
private:
b2Body* m_pBody;
};
//以上代码用“has-a”将渲染的精灵类和刚体绑定在一个类中,函数中先定义精灵类,然后定义刚体。
接下来需要在初始化方法里调用scheduleUpdate函数模拟出每个时间步更新,并在update函数中进行更新。
Box2D是通过定期调用step函数来更新动画的。
step函数的第一个参数是时间步。这里进行了修改,因为dt会不同,所以不建议用dt作为时间步,而要给它
一个固定的时间步才不会显得动画时快时慢。第二个参数是速度迭代次数,建议8次,超过10次的基本看不出
效果的提升。第三个参数是位置迭代,1次就可以。
时间步更新:
void Box2DTestLayer::update(float dt){
int velocityIterations = 8;
int positionIterations = 1;
world->Step(0.03,velocityIterations,positionIterations);
}
同时,渲染的函数也需要更新,在自己的nodeToParentTransform函数中更新节点位置。
更新节点位置:
CCAffineTransform PhysicsSprite::nodeToParentTransform(void){
b2Vec2 pos = m_pBody->GetPosition();
float x = pos.x * PTM_RATIO;
float y = pos.y * PTM_RATIO;
if(isIgnoreAnchorPointForPosition()){
x+=m_tAnchorPointInPoints.x;
y+=m_tAnchorPointInPoints.y;
}
float radians = m_pBody->GetAngle();
float c = cosf(radians);
float s = sinf(radians);
if(!CCPoint::CCPointEqualToPoint(m_tAnchorPointInPoints,CCPointZero)){
x += c*-m_tAnchorPointInPoints.x + -s*-m_tAnchorPointInPoints.y;
y += s&-m_tAnchorPointInPoints.x + c*-m_tAnchorPointInPoints.y;
}
m_tTransform = CCAffineTransformMake(c,s,-s,c,x,y);
return m_tTransform;
}
删除世界对象:
Box2DTestLayer::~Box2DTestLayer(){
delete world;
world = NULL;
}