cocos2d-x-3.2 Box2d物理引擎起步

来源:互联网 发布:php加密函数 编辑:程序博客网 时间:2024/05/20 07:35

理论介绍

        

在启动Box2d物理引擎前,我们需要进行如下操作

进入Visual Studio,选定HelloWorld工程,右键选择属性。然后在弹出的菜单中,选择C/C++ -->预处理器 -->预处理器定义,将预处理器定义中的CC_ENABLE_CHIPMUNK_INTEGRATION=1改成CC_ENABLE_BOX2D_INTEGRATION=1

然后再编译即可启动Box2d引擎,使用CHIPMUNK引擎同理。。

下面进行一下Box2D引擎介绍,蛤蟆看了一些资料,然后将这些资料提取出来和小伙伴们分享:

Box2D是一个用于模拟2D刚体物体的C++引擎。而物理引擎是一个动画的系统,这样就不需要由动画师去移动你的物体。你可以让物理引擎来做导演。

         此外,小伙伴们需要记住的是Box2D 是用C++ 来写成的。源码中定义的大部分类型都有b2前缀,注意区分。。

         物理世界的概念(以下摘自《Box2Dv2.0.1 用户手册.pdf》):

--------------------------------------------此处是分界线---------------------------------------------------

刚体(rigid body)

一块十分坚硬的物质,它上面的任何两点之间的距离都是完全不变的。它们就像****那样坚硬。在后面的讨论中,我们用物体(body)来代替刚体。

形状(shape)

一块严格依附于物体(body)的 2D 碰撞几何结构(collisiongeometry)。形状具有摩擦(friction)和恢复(restitution)的材料性质。

约束(constraint)

一个约束(constraint)就是消除物体自由度的物理连接。在 2D 中,一个物体有 3 个自由度。如果我们把一个物体钉在墙上(像摆锤那样),那我们就把它约束到了墙上。这样,此物体就只能绕着这个钉子旋转,所以这个约束消除了它 2 个自由度。

接触约束(contact constraint)

一个防止刚体穿透,以及用于模拟摩擦(friction)和恢复(restitution)的特殊约束。你永远都不必创建一个接触约束,它们会自动被 Box2D 创建。

关节(joint)

它是一种用于把两个或多个物体固定到一起的约束。Box2D 支持的关节类型有:旋转,棱柱,距离等等。关节可以支持限制(limits)和马达(motors)。

关节限制(joint limit)

一个关节限制(joint limit)限定了一个关节的运动范围。例如人类的胳膊肘只能做某一范围角度的运动。

关节马达(joint motor)

一个关节马达能依照关节的自由度来驱动所连接的物体。例如,你可以使用一个马达来驱动一个肘的旋转。

世界(world)

一个物理世界就是物体,形状和约束相互作用的集合。Box2D 支持创建多个世界,但这通常是不必要的。

--------------------------------------------此处是分界线---------------------------------------------------

蛤蟆补充几个:

夹具(fixture)

         夹具绑定一个形状Shape到一个Body,增加属性如密度,摩擦力和恢复特性。夹具将形状Shape带入到碰撞系统,这样Shape就能和其他形状进行碰撞了。

求解器(solver)

         这个相当于物理世界仲裁者,它来推进时间,计算约束。

 

蛤蟆再来介绍下这个Box2D中的代码,我想介绍完代码其他的操作使用就都是浮云了。

先来看下主要的头文件Box2D.h文件,这些文件在\cocos2d-x-3.2\external\Box2D路径下,该头文件包含了所有和Box2D物理引擎相关的头文件。

此外主要是3个模块,分别是collision,common和Dynamics。

Collision顾名思义就是碰撞相关的代码所在地,common文件夹是主要是分配、数学函数和设置所在地,而dynamics文件夹是主要的类定义场所,包括物理世界,刚体,关节等。

class b2Fixture;

class b2Joint;

class b2Contact;

class b2Controller;

class b2World;

class b2Body等

结构体

struct b2FixtureDef;

struct b2JointEdge;

struct b2ContactEdge;

struct b2BodyDef

         枚举类型

enum b2BodyType

         等,小伙伴们看到了么,都是用b2前缀开始的。

         OK,我们先简单学习一下,大概怎么使用,

创建函数如下:

b2Body* b2World::CreateBody(constb2BodyDef* def)

b2Joint* b2World::CreateJoint(constb2JointDef* def)

销毁函数如下:

void b2World::DestroyBody(b2Body* body)

void b2World::DestroyJoint(b2Joint* joint)

         重要的一点是Body的使用需要一下几个步骤:

1.      定义Body的位置和阻尼

2.      使用世界对象(b2world)创建之

3.      使用形状,摩擦力和密度来定义fixture.

4.      在Body上创建fixtures.

         依他类推,或者可以去Box2D官网看哦,不过蛤蟆觉得看完蛤蟆这些就差不多可以入个小门了哈,让我们开始吧。

具体步骤

         我们还是在HelloWorld.cpp文件中找,首先加入头文件如下:

#include <Box2D/Box2D.h>

接着选中解决方案右键->添加->添加现有项目,选择当前工程目录下的

\cocos2d\external\Box2D\proj.win32\Box2D.vcxproj。

         右键选中libBox2D 工程项目,然后点击生成libBox2D.lib库。

         完了之后,

选中我们项目工程右键属性->配置属性->连接器->输入->附加依赖项中,我们输入libBox2D.lib库名字。完毕。

然后到bool HelloWorld::init()函数,加入如下代码,不要怕,接下去蛤蟆会逐行解释哈。

                  b2Vec2 gravity(0.0f, -10.0f);

         b2World world(gravity);

         b2BodyDef groundBodyDef;

         groundBodyDef.position.Set(0.0f,-10.0f);

         b2Body* groundBody = world.CreateBody(&groundBodyDef);

         b2PolygonShape groundBox;

         groundBox.SetAsBox(50.0f,10.0f);

         groundBody->CreateFixture(&groundBox,0.0f);

         b2BodyDef bodyDef;

         bodyDef.type= b2_dynamicBody;

         bodyDef.position.Set(0.0f,4.0f);

         b2Body* body = world.CreateBody(&bodyDef);

         b2PolygonShape dynamicBox;

         dynamicBox.SetAsBox(1.0f,1.0f);

         b2FixtureDef fixtureDef;

         fixtureDef.shape= &dynamicBox;

         fixtureDef.density= 1.0f;

         fixtureDef.friction= 0.3f;

         body->CreateFixture(&fixtureDef);

         float32 timeStep = 1.0f / 60.0f;

         int32 velocityIterations = 6;

         int32 positionIterations = 2;

         for (int32 i =0; i < 60; ++i)

         {

                   world.Step(timeStep,velocityIterations, positionIterations);

                   b2Vec2 position = body->GetPosition();

                   float32 angle = body->GetAngle();

                   CCLog("%4.2f %4.2f %4.2f\n", position.x, position.y,angle);

  }

 

编译运行得到输出如下,当然这个蛤蟆没有图形化输出哈,下一次一定有高逼格的图形化输出。

0.00 4.00 0.00

 

0.00 3.99 0.00

 

0.00 3.98 0.00

 

0.00 3.97 0.00

 

0.00 3.96 0.00

 

0.00 3.94 0.00

 

0.00 3.92 0.00

 

0.00 3.90 0.00

 

0.00 3.87 0.00

 

0.00 3.85 0.00

 

0.00 3.82 0.00

 

0.00 3.78 0.00

 

0.00 3.75 0.00

 

0.00 3.71 0.00

 

0.00 3.67 0.00

 

0.00 3.62 0.00

 

0.00 3.57 0.00

 

0.00 3.52 0.00

 

0.00 3.47 0.00

 

0.00 3.42 0.00

 

0.00 3.36 0.00

 

0.00 3.30 0.00

 

0.00 3.23 0.00

 

0.00 3.17 0.00

 

0.00 3.10 0.00

 

0.00 3.02 0.00

 

0.00 2.95 0.00

 

0.00 2.87 0.00

 

0.00 2.79 0.00

 

0.00 2.71 0.00

 

0.00 2.62 0.00

 

0.00 2.53 0.00

 

0.00 2.44 0.00

 

0.00 2.35 0.00

 

0.00 2.25 0.00

 

0.00 2.15 0.00

 

0.00 2.05 0.00

 

0.00 1.94 0.00

 

0.00 1.83 0.00

 

0.00 1.72 0.00

 

0.00 1.61 0.00

 

0.00 1.49 0.00

 

0.00 1.37 0.00

 

0.00 1.25 0.00

 

0.00 1.13 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

0.00 1.01 0.00

 

 

 

代码解释

         下面我们来解释下代码的含义:

bool HelloWorld::init()函数中代码解释。

 

         //定义一个重力向量。

         b2Vec2 gravity(0.0f, -10.0f);

         //创建一个物理世界。接着我们可以在这个物理世界中添加东西了。

         b2World world(gravity);

         //创建一个接地气的body使用,这个要满足前面我们描述的4个步骤哦。

         //第一步:定义一个body,定义初始位置

         b2BodyDef groundBodyDef;

         groundBodyDef.position.Set(0.0f,-10.0f);

         //第二步:传递body定义到世界对象,以此创建一个body.body是静态的,不会与其他静态body碰撞,也不会移动。

         b2Body* groundBody = world.CreateBody(&groundBodyDef);

         //第三步:创建一个底面多边形,宽度为100units,长度为20units.

         b2PolygonShape groundBox;

         groundBox.SetAsBox(50.0f,10.0f);

         //第四步:创建一个夹具,我们可以直接将shape传递给body即可。第二个参数 0.0f表示密度。

记住,每个fixture必须有一个父亲body,即使fixtures 是静态的。当然,你可以把所有静态的fixtures添加到单个静态的body上。移动和修改body 上的fixture是不行的。

         groundBody->CreateFixture(&groundBox,0.0f);

         //创建一个动态的body

         b2BodyDef bodyDef;//第一步:定义body的属性,位置。

         bodyDef.type= b2_dynamicBody;//必须定义为b2_dynamicBody才能收到外力运动。

         bodyDef.position.Set(0.0f,4.0f);

         b2Body* body = world.CreateBody(&bodyDef);//第二步,创建body.

         //第三步:创建一个多边形Shape。设置属性

         //注意:动态的body必须有非零的密度,不然会非常的奇怪的。

         b2PolygonShape dynamicBox;

         dynamicBox.SetAsBox(1.0f,1.0f);

         b2FixtureDef fixtureDef;

         fixtureDef.shape= &dynamicBox;

         fixtureDef.density= 1.0f;

         fixtureDef.friction= 0.3f;

         //第四步:在body上创建一个夹具fixture.

         body->CreateFixture(&fixtureDef);

         //现在可以进行****了

         //需要设置一个时间步长,通常物理引擎的时间步长最慢1/60 秒。

         float32 timeStep = 1.0f / 60.0f;

         //之前我们介绍的概念中有个solver,在我们的约束solver中有两个

         //一个是速度相一个是位置相。我打个比方,物理移动都就我们才让solver计算一次呢?

         //这个就是需要设置的,一般速度相设置为8,位置相设置为3。主要是性能和质量的平衡。

         //这两个相是没有任何关系的。

         int32 velocityIterations = 6;

         int32 positionIterations = 2;

         //下面模拟一个1秒内的 60个时间步长(我们设置的时间步长是1/60f,所以1秒有60个时间点。

         for (int32 i =0; i < 60; ++i)

         {

                   world.Step(timeStep,velocityIterations, positionIterations);

                   b2Vec2 position = body->GetPosition();

                   float32 angle = body->GetAngle();

                   CCLog("%4.2f %4.2f %4.2f\n", position.x, position.y,angle);

         }

         OK,完毕,是不是有点头绪了,后续蛤蟆慢慢深入哈。

0 0