Cocos2D物理引擎box2d基本教程(一)

    作者:课课家教育更新于: 2019-03-27 20:21:12

      相信各位同学对于Cocos2D的物理引擎box2d都不是很熟悉,本篇教程将带你深入了解一下Cocos2D的物理引擎box2d。

      一、准备工作

      引入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项目。创建好之后运行:

    Cocos2D物理引擎box2d基本教程(一)_Cocos2D物理_Cocos2D_Cocos2D游戏开发_课课家

      每当我们点击屏幕时,会落下一个小方块,ok,然我们来详细看下生成的代码。

      -(id) init

      {

      // always call "super" init

      // apple recommends to re-assign "self" with the "super" return value

      if( (self=[super init])) {

      // enable touches

      self.isTouchEnabled = YES;

      // enable accelerometer

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

      // Do we want to let bodies sleep?

      // This will speed up the physics simulation

      bool doSleep = true;

      // Construct a world object, which will hold and simulate the rigid bodies.

      world = new b2World(gravity, doSleep);

      world->SetContinuousPhysics(true);

      // debug Draw functions

      m_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;

      // bottom

      groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));

      groundBody->CreateFixture(&groundBox,0);

      // top

      groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));

      groundBody->CreateFixture(&groundBox,0);

      // left

      groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));

      groundBody->CreateFixture(&groundBox,0);

      // right

      groundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));

      groundBody->CreateFixture(&groundBox,0);

      //Set up sprite

      CCSpriteBatchNode *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的四个边缘,防止物体跑出屏幕。再然后是创建精灵和一个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 images

      int 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 world

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

      // 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_ARRAY

      glDisable(GL_TEXTURE_2D);

      glDisableClientState(GL_COLOR_ARRAY);

      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

      world->DrawDebugData();

      // restore default GL states

      glEnable(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 world

      for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())

      {

      if (b->GetUserData() != NULL) {

      //Synchronize the AtlasSprites position and rotation with the corresponding body

      CCSprite *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没掉下去。

课课家教育

未登录