下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

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

作者:课课家教育     来源: http://www.kokojia.com点击数:2982发布时间: 2019-03-28 09:10:29

标签: Cocos2D物理Cocos2DCocos2D游戏开发

  相信各位同学对于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没掉下去。

赞(25)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程