李華明Himi 原創,轉載務必在明顯處註明:
轉載自【黑米GameDev街區】 原文連結: http://www.himigame.com/iphone-cocos2d/474.html
上一節講述了粒子的相關問題,當然啦,不示弱,今天繼續將物理系統給大家進行簡單的介紹和講述;
首先先介紹,如何在cocos2d中加入box2d開發lib包,因為一般使用cocos2d引擎進行開發遊戲時,大家建立項目都會選用cocos2d架構,而不是直接採用物理系統的cocos2d架構,但是後期忽然需要在項目中使用物理系統(這種情況很經常發生,至於為什麼,童鞋們都懂得~),OK,首先建立一個普通的cocos2d項目;
OK,加入box2d->lib步驟如下:
1. 首先將box2d的lib包拷貝到剛建立的項目下,然後右鍵項目的libs檔案夾進行匯入項目中;(如果你沒有box2d的lib包,那就建立一個cocos2d-box2d的項目就有了)
2.雙擊你的項目名預設開啟配置資訊視窗,點擊Build Settings標籤,然後在頁面中找到”Search Paths“一欄,然後在“User Header Search Paths”中添加“xx/libs”;這裡的XX是你的項目名稱;緊接著在“User Header Search Paths”一項的上面設定“Always Serch Paths”的選項 為YES,預設為NO;這裡務必要設定;
3.最後commadn+B (我用的xcode For lion)編譯項目代碼,如果提示編譯成功,OK,可以使用啦;
下面我來給大家簡單的介紹以下如何在cocos2d中使用Box2d物理系統,雖然關於Box2d的相關資料和教程很少,但是這裡我也不會很詳細的介紹和解釋,因為我即將上市的Android遊戲開發書籍中已經對Box2d進行了很詳細的講解和兩個物理小遊戲實戰,所以這裡就大概的介紹下一些重要的方法;
便於講解,這裡我直接使用Xcode直接建立一個cocos2d-Box2d的項目,然後簡單的修改:
//// HelloWorldLayer.mm// Box2dProject//// Created by 華明 李 on 11-9-14.// Himi//// Import the interfaces#import "HelloWorldLayer.h" #define PTM_RATIO 32// enums that will be used as tagsenum {kTagTileMap = 1, kTagAnimation1 = 1,};// HelloWorldLayer implementation@implementation HelloWorldLayer+(CCScene *) scene{ CCScene *scene = [CCScene node]; HelloWorldLayer *layer = [HelloWorldLayer node]; [scene addChild: layer]; return scene;}// on "init" you need to initialize your instance-(id) init{//初始化中,在螢幕上建立了物理世界,並且建立了在螢幕四周建立了剛體防止物理世界中的剛體超屏 //最後並且調用一個tick方法用於讓物理世界不斷的去類比if( (self=[super init])) { self.isTouchEnabled = YES; self.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);bool doSleep = true; 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; m_debugDraw->SetFlags(flags); b2BodyDef groundBodyDef;groundBodyDef.position.Set(0, 0); // bottom-left corner b2Body* groundBody = world->CreateBody(&groundBodyDef); 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); CCLabelTTF *label = [CCLabelTTF labelWithString:@"Himi" fontName:@"Marker Felt" fontSize:32];[self addChild:label z:0];label.position = ccp( screenSize.width/2, screenSize.height-50); [self schedule: @selector(tick:)];}return self;}//Box2d偵錯模式,因為物理世界是看不到摸不到的,那麼物理世界中的剛體其實也一樣無法看到,//但是為了便於開發調試,Box2d提供了調試類,主要作用是能將物理世界的所有剛體、關節等都利用線條框出來,//這樣便於設定你的Body與Sprite之間的位置關係 -----(void) draw{glDisable(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);}//---添加一個剛體,首先需要建立剛體的皮膚,可以理解這個皮膚是剛體的屬性,然後利用皮膚封裝出一個剛體-(void) addNewSpriteWithCoords:(CGPoint)p sp:(CCSprite*)sprite{CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y); sprite.position = ccp( p.x, p.y);b2BodyDef bodyDef;bodyDef.type = b2_dynamicBody;bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO); //將精靈資訊賦值給剛體皮膚,這樣就能讓精靈的運動軌跡與這個即將建立出的剛體在物理世界中的運動軌跡同步bodyDef.userData = sprite;b2Body *body = world->CreateBody(&bodyDef);b2PolygonShape dynamicBox;dynamicBox.SetAsBox(.9f, .9f); b2FixtureDef fixtureDef;fixtureDef.shape = &dynamicBox;fixtureDef.density = 1.0f;fixtureDef.friction = 0.3f;body->CreateFixture(&fixtureDef); //給body施加一個力 b2Vec2 force = body->GetWorldVector(b2Vec2(1000.0f, 600.0f)); b2Vec2 point = body->GetWorldPoint(b2Vec2(0.4f, 0.4f)); body->ApplyForce(force, point);//----------備忘1 Himi}//此方法中,首先是讓物理世界進行物理類比,然後不斷的遍曆物理世界中的剛體運動軌跡複製給對應的精靈-(void) tick: (ccTime) dt{int32 velocityIterations = 8;int32 positionIterations = 1; world->Step(dt, velocityIterations, positionIterations);for (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());}}}//---觸屏將添加一個body和精靈,位置為玩家觸屏的座標- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{for( UITouch *touch in touches ) {CGPoint location = [touch locationInView: [touch view]]; location = [[CCDirector sharedDirector] convertToGL: location]; CCSprite *sprite =[CCSprite spriteWithFile:@"icon.png"]; [self addChild:sprite];[self addNewSpriteWithCoords: location sp:sprite];}}- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration{static float prevX=0, prevY=0;//#define kFilterFactor 0.05f #define kFilterFactor 1.0f// don't use filter. the code is here just as an examplefloat accelX = (float) acceleration.x * kFilterFactor + (1- kFilterFactor)*prevX;float accelY = (float) acceleration.y * kFilterFactor + (1- kFilterFactor)*prevY;prevX = accelX;prevY = accelY;b2Vec2 gravity( -accelY * 10, accelX * 10);world->SetGravity( gravity );} - (void) dealloc{ delete world;world = NULL; delete m_debugDraw; [super dealloc];}@end
這裡我只是對重要的方法進行的說明,主要修改的一點地方在備忘1這裡,我這裡對每次玩家觸控螢幕幕的地方建立的剛體都進行施加了一個力,讓剛體進行運動,那麼這個運動的軌跡也會根據你設定的物理世界的重力方向發生改變,當前項目中,重力方向垂直下落,沒有X軸的變化;
還要注意一點,由於box2d是c++代碼,那麼如果你使用box2d的話,首先把你的Delegate.m的類改成Delegate.mm,還有你使用box2d相關代碼的實作類別(.m)格式的類要改成(.mm)格式才可,這樣編譯器就會知道是混合代碼,否則都當成object-c進行編譯就會報錯;
運行如下:
可以看出,在icon圖的周圍包圍著線段,這個就是Box2d提供的調試繪製,將本無形的剛體繪製出來了;
這裡我不得不說一些童鞋,例如之前我寫過Android上的一個自己隨手的物理系統小球的例子,我在博文中寫了要觸屏才建立小球,但是很多童鞋問我項目運行起來沒效果有問題,我就崩潰了。。。你們讓我
源碼本想上傳,但是發現一點擊上傳資源就悲劇打不開網頁,大家可以直接建立一個cocos2d-box2d的項目,然後將HelloWorldLayer.mm中代碼換成我上面的代碼即可~