Box2D C++教程6-定制器(Fixtures)

2023-11-08

Box2D C++教程6-定制器(Fixtures)

Box2D C++ 教程 6- 定制器 (Fixtures)

转载自: http://www.ohcoder.com/post/2012-06-13/40028695873

 

定制器 (Fixtures)

定制器用来描述场景中物体 (body) 的大小,形状,材质属性等。一个物体可以附加多个定制器,物体的质心会被附加定制器的顺序所影响。当两个物体相撞时,它们的定制器会决定它们的变化。定制器的主要属性如下:

·         形状 - 多边形或圆弧

·         恢复 - 定制器的弹力

·         摩擦 - 光滑程度

·         密度 - 物体大小的重量

我们会谈到上面的每一个概念,并对它们做一些实验(还有一个使定制器成为传感器的 isSensor 属性,之后教程里我会谈到它)。让我们就以上一次话题'Bodies' 作为起点,创建一个简单的动态物体作为开始吧。那么 FooTest 类的构造函数看起来会是下面这个样子:

FooTest() {

  b2BodyDef myBodyDef;

  myBodyDef.type = b2_dynamicBody; //this willbe a dynamic body

  myBodyDef.position.Set(-10, 20); //a littleto the left

                                           

  b2Body* dynamicBody1 =m_world->CreateBody(&myBodyDef);

}

形状 (Shapes)

当物体在场景中移动的时候,每一个定制器都会有一个用来进行碰撞检测的形状属性。形状可以是弧形或是多边形。让我们设置一个弧形 ...

b2CircleShape circleShape;

circleShape.m_p.Set(0, 0); //position, relative to bodyposition

circleShape.m_radius = 1; //radius

... 使用形状的定制器:

b2FixtureDef myFixtureDef;

myFixtureDef.shape =  &circleShape; //this is a pointer to the shape above

dynamicBody1->CreateFixture(&myFixtureDef);  //add a fixture to the body

现在运行程序,就像之前出现四边形的地方会有一个圆弧:

 

设置圆弧的坐标时,由于圆弧的位置与物体 (body) 的坐标位置有了关联 ( 译者注: 因为形状所附加的定制器同时被附加在物体上 ) 。虽然我们设置圆弧本身的初始坐标为 (0, 0) ,但是因为圆弧形状所附加的定制器同时被附加到位置在 (0, 20) 的物体上,所以圆弧也将被设置在坐标为 (0, 20) 的位置。

现在让我们尝试一下多边形。使用多边形,你可以单独的设置多边形的每一个顶点坐标来自定义形状,如果你想要盒子或者线形状,你可以使用快捷的方法进行创建。这里我们自定义了一个多边形的顶点:

b2Vec2 vertices[5];

vertices[0].Set(-1,  2);

vertices[1].Set(-1,  0);

vertices[2].Set( 0, -3);

vertices[3].Set( 1,  0);

vertices[4].Set( 1,  1);

                               

b2PolygonShape polygonShape;

polygonShape.Set(vertices, 5); //pass array to the shape

                               

myFixtureDef.shape = &polygonShape; //change theshape of the fixture

myBodyDef.position.Set(0, 20); //in the middle

b2Body* dynamicBody2 =m_world->CreateBody(&myBodyDef);

dynamicBody2->CreateFixture(&myFixtureDef); //adda fixture to the body

 

如果使用这种方式创建多边形定制器,这里有几个需要注意的事情。首先,默认情况下每个多边形的顶点为 8 个,如果你想要设置更多的顶点,需要修改b2Settings.h 头文件中的 b2_maxPolygonVertices 值,顶点必须以逆时针顺序排列,并且组成的是凸多边形。凸多边形的特点是,如果沿着任意一条边做直线,多边形均在直线的同侧(要么在左侧,要么在右侧)。

如果你想要一个四边形定制器,最简单的方法就是像之前提到的使用 SetAsBox 方法:

polygonShape.SetAsBox(2,  1); //a 4x2 rectangle

myBodyDef.position.Set(10,20);  //a bit to the right

                                

b2Body* dynamicBody3 =  m_world->CreateBody(&myBodyDef);

dynamicBody3->CreateFixture(&myFixtureDef);  //add a fixture to the body



注意 SetAsBox 中的参数指的是盒子的 “ 半宽 ” 和 “ 半高 ” ,而且它的中心点会被附加到物体上当做物体的中心点。另外还有一点需要注意,由于定制器对形状使用的是指针引用,所以对形状所做的任何改变,我们都不需要对定制器做额外的工作,所以这次我们不用做任何其它代码的设置。

有时候相对于实体多变性而言,有可能只想要一条 0 厚度的直线。这可以通过另外一个便利 SetAsEdge 的方法来实现,此方法指出了一条直线的两点。让我们创建一个静态的线形定制器,放到场景的底部,让动态的物体落到它的上面。

myBodyDef.type =  b2_staticBody; //change body type

myBodyDef.position.Set(0,0);  //middle, bottom

                                   

polygonShape.SetAsEdge(  b2Vec2(-15,0), b2Vec2(15,0) ); //ends of the line

b2Body* staticBody =  m_world->CreateBody(&myBodyDef);

staticBody->CreateFixture(&myFixtureDef);  //add a fixture to the body


注意 : SetAsEdge 创建多边形的方法已经在 Box2D 的 v2.1.2 版本之后取消了,因为这种单一的线形状已经给出了形状类型, b2EdgeShape 。可以使用b2EdgeShape 画出相等图形:

b2EdgeShape edgeShape;

edgeShape.Set(b2Vec2(-15,0),  b2Vec2(15,0));

                                     

myFixtureDef.shape =  &edgeShape;

密度 (Density)

到目前为止,你可能在纳闷,为什么我用鼠标光标拖拽物体的时候,物体不会像期望中的那样旋转呢?那是因为我们还没有为定制器设置任何密度值。物体的面积乘以密度然后变成定制器的质量。返回到我们第一次声明定制器的地方,然后设置密度值如下:

b2FixtureDef myFixtureDef;

...

myFixtureDef.density = 1;  //new code

既然所有物体都使用了相同的定制器进行了定义,它们所有都会受到同一个定制器所影响。

 

在这个例子中,所有定制器都有相同的密度,那就意味着它们的重量是由它们可见的形状所决定的,其中圆弧是最轻的一个。试着通过改变定制器的密度,看看如何设定物体的 ‘ 重量 ’ 。记住这是由于所有的物体都使用了相同的定制器,另外你还要确保每次调用 CreateFixture 方法之前设置定制器的相关属性。

多个定制器 (Multiple fixtures)

我们可以把这个三个定制器附加到同一个物体上,而且看起来非常简单 - 回到每次调用 CreateFixture 方法的地方,把对 dynamicBody1 , dynamicBody2 ,dynamicBody3 所做的附加操作全部更改到 dynamicBody1 上。

 

正如你所看到的这会让所有定制器关联到 dynamicBody1 物体上。很直观的看到所有定制器附着在它们的物体上,但是并不是必须一定要像这样。定制器可以被添加到物体的任何位置,甚至它们之间可以产生空隙。例如像之前一样,可以让它们之间产生同样的间隔,我们可以返回之前创建它们的位置,调整它们之间的位置。

//for the custom polygon,  add 10 to each x-coord

vertices[0].Set(-1  +10,  2);

vertices[1].Set(-1  +10,  0);

vertices[2].Set( 0 +10, -3);

vertices[3].Set( 1  +10,  0);

vertices[4].Set( 1  +10,  1);

...

//for the box, use an  extended version of the SetAsBox function which allows

//us to set a location and  angle (location is offset from body position)

polygonShape.SetAsBox(2, 1,  b2Vec2(20,0), 0); //moved 20 units right, same angle

运行的结果看起来像下面这个样子(这张插图很好的表现了调整后的定制器)。


摩擦 (Friction)

现在我们知道了如何为同一个物体设置多个定制器 (fixtures) ,让我们再次以一个空场景做为开始,在下面实验中为一个物体设置四个矩形定制器。

FooTest() {

    //set  up a dynamic body

    b2BodyDef  myBodyDef;

    myBodyDef.type  = b2_dynamicBody;

    myBodyDef.position.Set(0,  20); //middle

    b2Body*  dynamicBody = m_world->CreateBody(&myBodyDef);

                                        

    //prepare  a shape definition

    b2PolygonShape  polygonShape;

    b2FixtureDef  myFixtureDef;

    myFixtureDef.shape  = &polygonShape;

    myFixtureDef.density  = 1;

                                        

    //add  four square shaped fixtures around the body center

    for ( int i = 0; i < 4; i++) {

      b2Vec2  pos( sinf(i*90*DEGTORAD), cosf(i*90*DEGTORAD) ); //radial placement

      polygonShape.SetAsBox(1,  1, pos, 0 ); //a 2x2 rectangle

      dynamicBody->CreateFixture(&myFixtureDef);  //add a fixture to the body

    }

                                        

    //make  a static floor to drop things on

    myBodyDef.type  = b2_staticBody;

    myBodyDef.position.Set(0,  0); //middle, bottom

    b2Body*  staticBody = m_world->CreateBody(&myBodyDef);

    polygonShape.SetAsEdge(  b2Vec2(-15,0), b2Vec2(15,3) ); //slightly sloped

    staticBody->CreateFixture(&myFixtureDef);  //add a fixture to the body

  }

在这个场景中,你会开到物体沿着斜坡滑下来。当定制器和地面接触的时候,定制器中的摩擦系数会用来计算物体的滑动速度。摩擦系数的大小可以设置在 0~1 之间, 0 意味着完全没有摩擦。当两个物体发生碰撞接触的时候,摩擦的结果往往是向摩擦系数低的方向运动。

试着给定制器定义零摩擦系数:

myFixtureDef.density = 1;

myFixtureDef.friction = 0;  //new code

这次物体的旋转会小很多而且根本不能在斜坡上停留,在下滑的过程中速度没有任何损耗。现在

试着把摩擦系数的值设置为 1 进行比较。最终,说明摩擦系数是定制器的独立属性和物体自身无关,那么为每一个定制器设置不同的摩擦系数如何呢? - 在之前CreateFixture 方法中添加一行如下代码:

myFixtureDef.friction =  i/4.0;

通过对上面物体的演示,你需要设置每个定制器的摩擦系数。

* 注意:摩擦系数为 1 并不能保证每次都没有滑动出现。

恢复 (Restitution)

恢复衡量了定制器 ‘ 弹性 ’ 的大小。像摩擦一样,恢复系数的也控制在 0~1 之间, 0 意味着定制器根本没有弹性, 1 意味着无能量损失,全部反弹回来。当两个定制器发生碰撞,碰撞的反弹的结果方向总由恢复系数更高的定制器决定。

可以像上面设置摩擦系数值一样对恢复系数做一些实验。为每一个定制器设置不同的恢复系数。

myFixtureDef.friction = ...;

myFixtureDef.restitution =  0; //new code

* 注意:恢复系数为 0 并不总是意味着没有反弹

* 注意:现实中少量的能量会在反弹过程中损耗

运行中改变定制器属性

有时候在游戏中,你可能希望在某个事件发生时修改定制器的属性。你可以通过定制器中的 setter 方法来改变摩擦系数,密度系数以及恢复系数。如果你已经有了那个需要改变的定制器的引用,那么你可以轻易的像这样进行改变:

fixture->SetDensity( ...  );

fixture->SetRestitution(  ... );

fixture->SetFriction( ...  );

如果你只有物体的引用,你需要像下面代码实例那样遍历物体的所有定制器来找到你想要改变的那个定制器。

* 设置密度需要有一个额外的操作步骤,当你想要让修改产生效果时,首先通过定制器的 SetDensity() 方法进行值的设置,然后需要调用定制器所附加的物体上的ResetMassData() 方法才能产生效果。

遍历物体的定制器

如果你有一个物体,并且想查看附加在物体上的所有定制器,你可以像下面这样做。 GetFixtureList() 方法返回物体上定制器链表的第一个元素。

for (b2Fixture*  f = body->GetFixtureList(); f; f = f->GetNext())

{

    //do  something with the fixture 'f'

}

如果你知道物体上只有一个定制器,你只要获取定制器链表的第一个元素就可以了:

b2Fixture* f =  body->GetFixtureList();

//do something with the  fixture 'f'

清除

如果你想要从一天物体身上移除定制器,那么就调用物体自身的 DestroyFixture方法:

b2Fixture*  myFixture = dynamicBody->CreateFixture(&myFixtureDef);

...

dynamicBody->DestroyFixture(myFixture);

记住做完此操作之后就不要在使用此定制器的指针!如果你销毁了物体,那么附加在物体上的所有定制器也会被销毁,同样也不要在使用定制器的指针。

通常情况下,如果你了解游戏的逻辑,并且了解物体是如何被销毁的,就可以合理安排程序尽量避免使用野指针。不过即便你工作的是一个复杂的项目,你也可以通过使用 Box2D 中提供的 “destruction listener” 特性来轻松搞定。这个特性会在定制器每次销毁的时候通知你,然后你就知道不要再使用这个定制器了。相关方法可以在 用户手册 的 “Loose Ends” 一章中查看 “Implicit destruction” 的使用

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Box2D C++教程6-定制器(Fixtures) 的相关文章

  • Cocos2dx隐藏iOS7状态栏】通过添加Plist Key隐藏iOS7状态栏

    本站文章均为李华明Himi原创 转载务必在明显处注明 作者新浪微博 李华明Himi 转载自 黑米GameDev街区 原文链接 http www himigame com e9 9a 8f e7 ac 94 1481 html 点击订阅 本博
  • 4.3.1 位置变化动作

    4 3 1 位置变化动作 2013 05 21 10 12 火烈鸟网络科技 人民邮电出版社 我要评论 0 字号 T T Cocos2d x高级开发教程 第4章动作 在这一章中 我们将为大家详细介绍各种动作的使用方法 读完本章后 读者将会学到
  • Unity3D的断点调试功能

    Unity3D的断点调试功能 2013 03 14 16 27 51 分类 Unity教程 标签 unity monodevelop 断点调试 debug 举报 字号 订阅 断点调试功能可谓是程序员必备的功能了 Unity3D支持编写js和
  • Cocos2d-x Js Binding 的手动绑定实现

    http www ityran com archives 4902 Cocos2d x Js Binding 的手动绑定实现 一叶 cocos2d x 08 13 2304 4条评论 随着 Cocos2d x 的发展 Cocos2d htm
  • cocos2d中的anchorPoint

    cocos2d中的anchorPoint 将该图片放置到屏幕左下方 CCSprite sprite CCSprite sprite Default png addChild sprite 生成的精灵放置在 0 0 也就是屏幕左下角 但是精灵
  • CCMoveBy和CCMoveTo有什么区别?

    CCMoveBy和CCMoveTo有什么区别 cocos2d里面的CCMoveBy 和CCMoveTo有什么区别 含义不同的地方在那块 那位高人给解释一下 谢谢 insul 2010 09 14 18 52 by是相对于当前位置 to是到该
  • cocos2d-x位图字体生成工具Bitmap Font Generator的使用(内含命令行)

    欢迎转载 本帖地址 http blog csdn net jinjian2009 article details 9371691 刚才发完贴发现 图全没了 原来自己直接贴的 没有上传 现在补全了 说下本文 重点就是命令行 如果用过这个工具的
  • pvr 与 png 的内存占用

    原文链接 http blog sina com cn s blog 6fbe210701015j7z html Zwoptex 生成的 spritesheet 除了可以导出 png 格式的图片外还有 pvr 格式 pvr 格式是 iOS 的
  • android Intent启动flag

    android Intent启动flag 分类 android框架 2013 10 30 14 47 1318人阅读 评论 0 收藏 举报 FLAG GRANT READ URI PERMISSION 如果设置这个标记 Intent的接受者
  • cocos2d-x实例学习(8)之CCJumpTo和CCJumpBy

    CCJumpTo和CCJumpBy概念 CCJumpTo 把某一CCSprite跳到某一位置 CCJumpBy 把某一CCSprite跳起一段距离 它有一个方法reverse 它让对象按原路径返回 CCJumpTo和CCJumpBy示例 创
  • Cocos2dx-OpenGL ES2.0教程:编写自己的shader(2)

    在上篇文章中 我给大家介绍了如何在cocos2d x里面绘制一个三角形 当时我们使用的是cocos2d x引擎自带的shader和一些辅助函数 在本文中 我将演示一下如何编写自己的shader 同时 我们还会介绍VBO 顶点缓冲区对象 和V
  • Openframework在VS2010中的配置

    Openframework在VS2010中的配置 首先去官网下载Openframework 下载后最好解压到C盘根目录下 不然会出现各种问题 我也不知道怎么解决 随便打开其中的例程 然后右击该工程 选择属性 如下图 接着在C C 常规选项里
  • COCOS2DX学习之Box2D物理引擎-------物体和相互作用

    1 创建一个静态物体 创建一个静态物体应该很简单 在头文件生命一下要创建新物体的函数 然后在cpp文件中实现它即可 具体的时候先过程 首先要用createbody函数创建一个物体 然后定义一个b2bodydef变量 指定一下这个变量的typ
  • 暂停时快速高斯模糊[关闭]

    Closed 这个问题需要调试细节 目前不接受答案 In cocos2d x我需要实现快速高斯模糊 它应该是这样的 我刚刚在 App Store 上发现了一些游戏 已经统一完成了这样的模糊 所以 这很好fadeIn fadeOut当用户暂停
  • 序列化 CDT 项目设置时遇到了

    当我构建项目时 我收到此错误 Serializing CDT Project settings has encountered a problem Null Pointer Exception 我正在使用最新的 eclipse 并尝试为 A
  • Cocos2D-x 3.0 中图元和精灵的 Z 索引不一致?

    我有两层 每个图层都有一个使用 OpenGL 进行的原始绘图 如下所示 void Layer1 drawPolygon glLineWidth 1 DrawPrimitives setDrawColor4B 255 255 255 255
  • 如何使用 Marmalade 编译 Cocos2d-X?

    有谁知道教程 或者三个简单的步骤来编译我用 Cocos2d x 和 Marmalade 编写的代码 我想将我已经在 Cocos2d X 中编译和使用的代码插入到 marmalade 项目中 然后进行编译 很多地方都写得很简单 但我却很难做到
  • 设置 Cygwin + Android NDK + cocos2Dx 以与 Eclipse 配合使用

    我正在关注该网站的教程 通过游戏应用货币化 作者 Todd Perkins http www lynda com Android tutorials Understanding downloading Cocos2d x 107169 12
  • Android 找不到类“android.app.job.JobScheduler”

    我在使用选项构建 apk 文件时不断收到此错误minifyEnabled true 应用程序构建过程和安装已成功 但无法启动并出现此错误 我已经厌倦了寻找班级图书馆 我对Android应用程序开发不太熟悉 请帮助我 错误堆栈跟踪 05 11
  • 安卓后退按钮不起作用

    我正在使用 cocos2dx 制作一个小游戏 在游戏的活动中我提供以下函数来处理后退按钮 Override public boolean onKeyDown int keyCode KeyEvent event return super o

随机推荐