一、準備工作
引入box2d包,在需要使用box2d的檔案中加入box2d的標頭檔;由於box2d是c++編寫的,所以要把引入box2d的所有檔案尾碼名都改為.mm
二、box2d中的一些重要參數
1、gravity,重力加速度,同現實世界中的g,向量
2、shape,形狀,形狀是有大小的
3、density,密度
4、friction,摩擦力
5、restitution,恢複,此參數用於碰撞,如果兩個物體有不同的restitution,box2d總是選擇比較大的restitution進行計算
6、meter,距離單位,靈活定義你的meter,當對象為0.1至10meters的時候,box2d可以很好的處理它們,
三、box2d之hello world
讓我們先建立一個box2d項目。建立好之後運行:
每當我們點擊螢幕時,會落下一個小方塊,ok,然我們來詳細看下產生的程式碼。
-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super init])) {// enable touchesself.isTouchEnabled = YES;// enable accelerometerself.isAccelerometerEnabled = YES;CGSize screenSize = [CCDirector sharedDirector].winSize;CCLOG(@"Screen width %0.2f screen height %0.2f",screenSize.width,screenSize.height);// Define the gravity vector.b2Vec2 gravity;gravity.Set(0.0f, -10.0f);// Do we want to let bodies sleep?// This will speed up the physics simulationbool doSleep = true;// Construct a world object, which will hold and simulate the rigid bodies.world = new b2World(gravity, doSleep);world->SetContinuousPhysics(true);// Debug Draw functionsm_debugDraw = new GLESDebugDraw( PTM_RATIO );world->SetDebugDraw(m_debugDraw);uint32 flags = 0;flags += b2DebugDraw::e_shapeBit;//flags += b2DebugDraw::e_jointBit;//flags += b2DebugDraw::e_aabbBit;//flags += b2DebugDraw::e_pairBit;//flags += b2DebugDraw::e_centerOfMassBit;m_debugDraw->SetFlags(flags);// Define the ground body.b2BodyDef groundBodyDef;groundBodyDef.position.Set(0, 0); // bottom-left corner// Call the body factory which allocates memory for the ground body// from a pool and creates the ground box shape (also from a pool).// The body is also added to the world.b2Body* groundBody = world->CreateBody(&groundBodyDef);// Define the ground box shape.b2PolygonShape groundBox;// bottomgroundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));groundBody->CreateFixture(&groundBox,0);// topgroundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));groundBody->CreateFixture(&groundBox,0);// leftgroundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));groundBody->CreateFixture(&groundBox,0);// rightgroundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));groundBody->CreateFixture(&groundBox,0);//Set up spriteCCSpriteBatchNode *batch = [CCSpriteBatchNode batchNodeWithFile:@"blocks.png" capacity:150];[self addChild:batch z:0 tag:kTagBatchNode];[self addNewSpriteWithCoords:ccp(screenSize.width/2, screenSize.height/2)];CCLabelTTF *label = [CCLabelTTF labelWithString:@"Tap screen" fontName:@"Marker Felt" fontSize:32];[self addChild:label z:0];[label setColor:ccc3(0,0,255)];label.position = ccp( screenSize.width/2, screenSize.height-50);[self schedule: @selector(tick:)];}return self;}
init方法首先建立了重力加速度,加速度是一個向量,-10是因為加速度朝向y軸負方向。之後建立world以及word的四個邊緣,防止物體跑出螢幕。再然後是建立精靈(這裡用到了之前一篇部落格的建立精靈方法,如果有疑問,傳送門:http://blog.csdn.net/volcan1987/article/details/7727593)和一個label,然後schedule tick方法
建立body的步驟
建立fixture步驟
知道了這些,讓我們來看看如何建立一個box2d世界中的物體
-(void) addNewSpriteWithCoords:(CGPoint)p{CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [self getChildByTag:kTagBatchNode];//We have a 64x64 sprite sheet with 4 different 32x32 images. The following code is//just randomly picking one of the imagesint idx = (CCRANDOM_0_1() > .5 ? 0:1);int idy = (CCRANDOM_0_1() > .5 ? 0:1);CCSprite *sprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake(32 * idx,32 * idy,32,32)];[batch addChild:sprite];sprite.position = ccp( p.x, p.y);// Define the dynamic body.//Set up a 1m squared box in the physics worldb2BodyDef bodyDef;bodyDef.type = b2_dynamicBody;bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);bodyDef.userData = sprite;b2Body *body = world->CreateBody(&bodyDef);// Define another box shape for our dynamic body.b2PolygonShape dynamicBox;dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box// Define the dynamic body fixture.b2FixtureDef fixtureDef;fixtureDef.shape = &dynamicBox;fixtureDef.density = 1.0f;fixtureDef.friction = 0.3f;body->CreateFixture(&fixtureDef);}
可以看到,代碼中的步驟跟我們上面的步驟一樣,唯一不同的就是多了一個userData,這個屬性用來綁定精靈否則你會看到精靈在你點擊的地方不動,而一個粉色的方塊掉了下去。fixture是相對於body的位置來的
下面這段代碼相對固定,可以先不管
-(void) draw{// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY// Needed states: GL_VERTEX_ARRAY, // Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAYglDisable(GL_TEXTURE_2D);glDisableClientState(GL_COLOR_ARRAY);glDisableClientState(GL_TEXTURE_COORD_ARRAY);world->DrawDebugData();// restore default GL statesglEnable(GL_TEXTURE_2D);glEnableClientState(GL_COLOR_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);}
接下來是tick方法
-(void) tick: (ccTime) dt{//It is recommended that a fixed time step is used with Box2D for stability//of the simulation, however, we are using a variable time step here.//You need to make an informed choice, the following URL is useful//http://gafferongames.com/game-physics/fix-your-timestep/int32 velocityIterations = 8;int32 positionIterations = 1;// Instruct the world to perform a single step of simulation. It is// generally best to keep the time step and iterations fixed.world->Step(dt, velocityIterations, positionIterations);//Iterate over the bodies in the physics worldfor (b2Body* b = world->GetBodyList(); b; b = b->GetNext()){if (b->GetUserData() != NULL) {//Synchronize the AtlasSprites position and rotation with the corresponding bodyCCSprite *myActor = (CCSprite*)b->GetUserData();myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());}}}
先說下step方法,velocityIterations和positionIterations這兩個參數越大,box2d就能進行更好的類比,但是效能就會下降,這兩個參數你應該自己把握以適合你的遊戲。
下面的迴圈是為了讓你的sprite與box2d中的對象同步,你可以注釋掉這段代碼看下效果,你會發現粉方塊掉下去了,你的sprite沒掉下去。
ok,今天先這麼多,沒想到想著挺簡單,卻寫了這麼久,有時間繼續!