【cocos2d-x官方文档】Box2D

【cocos2d-x官方文档】Box2D

本章由 浅底 (泰然教程组)翻译,转载请注明出处并通知泰然。

Box2D是一个用于游戏的二维刚体模拟库。 cocos2d-X程序员可以在他们的游戏使用它,使物体以可信的方式移动,使游戏世界互相作用。
Box2D是用轻便的C++编写的,下面的教程,由Ray Wenderlich编写,展示了如何在游戏中使用box2d,原来的文章是“How To Create A Breakout Game with Box2D and Cocos2D”。

Part 1Part 2.

在这里,在示例代码中我们只翻译Objective-C到C++。

您可以下载https://github.com/clawoo/BreakoutCocos2D-x

Box2D的世界
你需要做的第一件事是在cocos2d-X中为Box2D创建一个世界对象,世界对象是Box2D的主要对象,它管理所有的物理刚体和模拟。
当我们创建了一个世界中的对象,我们还需要指定一个初始的重力矢量。

   
   
  1. // Define the gravity vector.
  2. b2Vec2 gravity;
  3. gravity.Set(0.0f, 0.0f);//No gravity
  4.  
  5. // Do we want to let bodies sleep?
  6. bool doSleep = true;
  7. // create a world object, which will hold and simulate the rigid bodies.
  8. _world = new b2World(gravity, doSleep);

一旦我们创建世界对象,我们就可以为世界添加一些刚体。刚体可以代表任何移动的对象,像忍者或怪物,也有静态刚体如平台或墙壁。
创建一个刚体
你只需要5个步骤来建立一个刚体 – 创建刚体的定义,一个刚体对象,形状,一个夹具定义,以及一个夹具对象。

首先创建一个刚体定义,指定如位置或速度的初始属性。
b2Body * _paddleBody;

一旦你设置好了,你可以通过刚体的定义使用世界对象创建一个刚体对象。

   
   
  1. // Create paddle body
  2. b2BodyDef paddleBodyDef;
  3.  
  4. paddleBodyDef.type = b2_dynamicBody;
  5. paddleBodyDef.position.Set(winSize.width/2/PTM_RATIO, 50/PTM_RATIO);
  6. paddleBodyDef.userData = paddle;
  7. _paddleBody = _world->CreateBody(&paddleBodyDef);
  8. //然后你创建一个形状,代表你要模拟的几何体
  9. // Create shape definition and add to body
  10. b2FixtureDef paddleShapeDef;
  11. paddleShapeDef.shape = &paddleShape;
  12. paddleShapeDef.density = 10.0f;
  13. paddleShapeDef.friction = 0.4f;
  14. paddleShapeDef.restitution = 0.1f;

然后,您可以创建一个夹具定义 – 设置夹具定义的形状为你刚刚设好的形状,并设置其他属性,如密度或摩擦。

   
   
  1. b2Fixture *_paddleFixture;

最后,你可以通过指定的夹具定义使用用刚体对象来创建一个夹具对象。

   
   
  1. _paddleFixture = _paddleBody->CreateFixture(&paddleShapeDef);

请注意,您可以添加许多夹具对象到一个单独的刚体对象。当创建复杂的对象时,就派上用场了。
一旦你添加了要添加到世界的对象,通常只要你用周期性的调用Step,这样它就有处理时间,Box2d就有制造”模拟魔法“的能力了。

所以让我们来看看tick中的代码:

   
   
  1. int velocityIterations = 8;
  2. int positionIterations = 1;
  3. // Instruct the world to perform a single step of simulation. It is
  4. // generally best to keep the time step and iterations fixed. _world->Step(dt, velocityIterations, positionIterations);
  5. bool blockFound = false;
  6. // Iterate over the bodies in the physics world
  7. for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext())
  8. {
  9. if (b->GetUserData() != NULL) {
  10. // Synchronize the AtlasSprites position and rotation with the corresponding body
  11. CCSprite* myActor =
  12. (CCSprite*)b->GetUserData();myActor->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );
  13. myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );
  14. if (myActor->getTag() == 1)
  15. {
  16. static int maxSpeed = 10;
  17. b2Vec2 velocity = b->GetLinearVelocity();
  18. float32 speed = velocity.Length();
  19. if (speed > maxSpeed) {
  20. b->SetLinearDamping(0.5);
  21. } else if (speed < maxSpeed) {
  22. b->SetLinearDamping(0.0);
  23. }
  24. }
  25. if (myActor->getTag() == 2) {
  26. blockFound = true;
  27. }
  28. }

我们在Box2D使用弧度(π弧度= 180度,所以X弧度* 180 /π给出了相应的角度),所以CC_RADIANS_TO_DEGREES将弧度转为角度。
在这里我们调用Steps函数,你可以设置两个的参数(velocityIterations和positionIterations)成更低或更高。它设置较低的结果是模拟细节会少一些,但是速度会增加。接下来,我们将遍历世界中的所有刚体,寻找它们的user data,一旦我们找到,我们会更新精灵的位置和角度来相匹配对应的物理模拟。
Box2D和碰撞
要找出Box2D中一个夹具与另一个夹具碰撞,我们需要注册一个接触监听器。一个接触监听器是一个Box2D的的C++对象,当两个对象开始接触,并停止接触时它会调用该对象的方法让我们知道。我们不能只储存发送到监听器的接触点的引用,因为它们是由Box2D重用的。所以,我们必须使用副本。

   
   
  1. void MyContactListener::BeginContact(b2Contact* contact)
  2. {
  3. // We need to copy out the data because the b2Contact passed in
  4. // is reused.
  5. MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
  6. _contacts.push_back(myContact);
  7. }

以下遍历所有的缓冲的接触点,并检查看是否其中一个是球,一个是屏幕底部。

   
   
  1. void MyContactListener::EndContact(b2Contact* contact)
  2. {
  3. MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
  4. std::vector<MyContact>::iterator pos;
  5. pos = std::find(_contacts.begin(), _contacts.end(), myContact);
  6. if (pos != _contacts.end())
  7. {
  8. _contacts.erase(pos);
  9. }
  10. }

在Helloworld.cpp,“tick”方法中,将使用_contactListener来得到碰撞刚体的接触点,如果一个block与球相交,则把这个block加到要销毁的对象列表中。

   
   
  1. b2Body *bodyA = contact.fixtureA->GetBody();
  2. b2Body *bodyB = contact.fixtureB->GetBody();
  3. if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
  4. CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
  5. CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
  6. // Sprite A = ball, Sprite B = Block
  7. if (spriteA->getTag() == 1 && spriteB->getTag() == 2) {
  8. if (std::find(toDestroy.begin(), toDestroy.end(), bodyB)
  9. == toDestroy.end()) {
  10. toDestroy.push_back(bodyB);
  11. }
  12. }
  13. // Sprite B = block, Sprite A = ball
  14. else if (spriteA->getTag() == 2 && spriteB->getTag() == 1) {
  15. if (std::find(toDestroy.begin(), toDestroy.end(), bodyA)
  16. == toDestroy.end()) {
  17. toDestroy.push_back(bodyA);
  18. }
  19. }

现在在你的游戏中可以更多的使用Box2d的技术。我期待着看到你们的一些很酷的物理游戏!

转载地址:http://www.ityran.com/archives/3622

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值