收藏 分享(赏)

Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注.doc

上传人:kpmy5893 文档编号:7330017 上传时间:2019-05-15 格式:DOC 页数:61 大小:340.50KB
下载 相关 举报
Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注.doc_第1页
第1页 / 共61页
Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注.doc_第2页
第2页 / 共61页
Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注.doc_第3页
第3页 / 共61页
Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注.doc_第4页
第4页 / 共61页
Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注.doc_第5页
第5页 / 共61页
点击查看更多>>
资源描述

1、原文地址:http:/ 网上已经有个 Box2D 用户手册的翻译,但是基于 v2.0.1,跟最新手册有很多不对应。在这里决定将文档的全文再翻译出来,更准确的说是根据网上流传的 v2.0.1版本,将最新文档重新整理一遍。很多内容是直接复制自Box2D v2.0.1 用户手册原文:Box2D v2.0.2 User Manual译者:Aman JIANG(江超宇)Box2D v2.1.0 用户手册版权 2007-2010 Erin Catto第01章 导言(Introduction)1.1 关于Box2D 是个二维刚体仿真库, 用于编写游戏。程序员可以使用它, 让游戏中的物体运动起来更真实, 让游

2、戏世界更具交互性。以游戏的角度来看,物理引擎只是个程序性动画系统。(procedural animation)(译注: 做动画常有两种方法, 一种是预先准备好动画所需的数据,比如图片,再一帧一帧地播放。另一种是以一定方法,动态计算出动画所需的数据,根据数据再进行绘图。 从这种角度看,预先准备的,可称为数据性动画,动态计算的可称为程序性动画。这个区别,就类似以前我们做历史题和数学题,做历史题,记忆很重要,也就是答案需要预先准备好的。做数学题,方法就很重要,答案是需要用方法推导出来的。 Box2D 就是用物理学的方法,推导出那游戏世界物体的位置,角度等数据。而 Box2D 也仅仅推导出数据,至于得

3、到数据之后怎么处理就是程序员自己的事情了。)Box2D 用可移植的 C+来写成,它定义的大部分类型都有 b2前缀, 希望这能有效消除Box2D 和你自己的游戏引擎之间的名字冲突。1.2 先备条件(Prerequisites)在此手册中,我假定你已经熟悉了基本的物理概念 ,比如质量 (mass),力(force), 扭矩(torque)和冲量(impulses) 。如果没有 , 建议读一下 Chris Hecker 和 David Baraff (google 这些名字) 的教程, 你不需要理解得非常细致 , 只需很好地了解一些基本概念 , 帮助你使用 Box2D。Wikipedia 也是个很好

4、的地方,去获取物理和数学知识。Wikipedia 的内容经过了精心的整理,在某些方面可能比 google 更有用。在 Game Developer Conference 上, Box2D 是作为物理教程的一部分而创建的。你可以从box2d.org 的下载区得到这些教程。Box2D 是使用 C+写成的, 因此也假定你具备 C+编程经验。Box2D 不应该是你的第一个 C+程序项目。你应该能熟练地编译 ,链接和调试。注意Box2D 不应该是你的第一个 C+项目。在使用 Box2D 之前, 请先学习 C+程序设计, 还要学习怎么去编译, 连接和调试。网上有很多这方面的资料。1.3 关于本手册本手册涵

5、盖了大多数 Box2D 的 API,但并非每个方面都涉及到。Box2D 自带了 testbed 例子, 鼓励你去看看, 以便了解更多。另外, Box2D 的代码注释已被整理过 , 符合 Doxygen程序的格式要求, 所以很容易就可以创建一个有超链接的 API 文档。1.4 反馈及错误报告如果你想反馈 Box2D 的任何内容,请在论坛里留下意见。这也是个交流讨论的好去处。Box2D 使用了 Google code project 进行问题跟踪。这是个跟踪问题的好方法, 保证你的反馈不会被淹没在论坛深处而无人理会。反馈地址: http:/ 就越有可能得到修复。假如有个测试例子将问题重现, 就更好

6、了。1.5 核心概念(Core Concepts)Box2D 中有一些基本对象, 这里我们先做一个简要的定义, 随后的文档会有更详细的描述。形状(shape)2D 几何对象, 比如圆形(circle)或多边形(polygon)。刚体(rigid body)十分坚硬的物质, 坚硬得像钻石,它上面任意两点之间的距离都保持不变。在后面的讨论中,我们用物体(body)来代替刚体。夹具(fixture)fixture 将形状绑定到物体之上, 并有一定的材质属性, 比如密度(density), 摩擦(friction)和恢复(restitution)。(译注:一个物体和另一物体碰撞, 碰撞后速度和碰撞前速

7、度的比值会保持不变,这比值就叫恢复系数。)约束(constraint)约束是个物理连接, 用于消除物体的自由度。在 2D 中, 物体有 3个自由度( 水平,垂直,旋转)。如果我们把一个物体钉在墙上( 像钟摆那样), 那就把它约束到了墙上。这个时候 ,此物体就只能绕着钉子旋转, 所以这个约束消除了它 2个自由度。(译注:简单的说, 需要用几个参数来确定物体的空间状态, 这个物体就有几个自由度。在二维中,完全没有约束的条件下, 我们要确定物体的状态, 要有 x 坐标, y 坐标, 旋转角这三个参数, 所以自由度为3。如果物体被钉在墙上, 只要有旋转角,就可以完全确定物体的状态,有了钉子这个约束,物

8、体自由度就变成了1。)接触约束(contact constraint)一种特殊的约束, 设计的目的是为了防止刚体被穿透 , 也用于模拟摩擦和恢复。接触约束不用你来创建, 它们会自动被 Box2D 生成。关节(joint)关节就是种约束, 用于将两个或多个 body 固定到一起。Box2D 支持不同的关节类型: 转动(revolute),棱柱(prismatic),距离(distance)等。一些关节可以有限制 (limits)和马达(motors)。关节限制(joint limit)关节限制限定了一个关节的运动范围。例如人类的胳膊肘只能在某一角度范围内运动。关节马达(joint motor)根

9、据关节的自由度, 关节马达可以驱动关节所连接的物体。例如, 你可以使用一个马达来驱动一个肘的旋转。世界(world)一个物理世界就是各种, 刚体 (bodies), 夹具(fixtures), 约束(constraints)相互作用的集合。 Box2D 支持创建多个世界, 但这通常没有必要。libgdx 核心概念应用到游戏之初步理解:1、 利用 world 模拟创建游戏的物理世界;2、 利用 body 创建各种通用物体;3、 利用 fixtures 给予通用物体基本属性(密度、摩擦力)以仿真各种真实物体;4、 利用 joint 将两个或多个物体(body )关联到一起,创建组合一起运动的物体,

10、如旋转机器人,类似使用组合多个图片实现动画效果的物体。5、 当游戏中各种物体状态发生改变,导致出现碰撞时,contact 及 contact constraint 就出现了,contact 用来表示两个物体之间出现了碰撞,contact constraint 用于限制碰撞的影响范围。6、 通常游戏需要对物体的碰撞进行处理,以实现游戏效果,此时需要利用 Contact Listener 相应的接口消除部分物体的碰撞、记录发生碰撞的物体状态以立即实现游戏效果。1.6 模块(Modules)Box2D 由三个模块组成:公共(Common)、碰撞(Collision)、和动态(Dynamics) 。C

11、ommon模块包括了内存分配、数学计算和配置。Collision 模块定义了形状 (shapes)、broad-phase检测和碰撞功能/查询(collision functions/queries)。最后,Dynamics 模块提供对世界(world)、刚体(bodies)、夹具(fixtures)和关节(joint) 的模拟。(译注: Broad Phase 是碰撞检测的一个子阶段, 将空间分割, 每个空间对应一个子树, 物体就放到树中, 不同子树内的物体不可能相交不用去计算 , 在同一个子树由对应的算法再计算出接触点等信息。因为这是远距碰撞检测,就叫 Broad Phase, 接下来还有

12、 Narrow Phase。)1.7 单位Box2D 使用浮点数, 所以必须使用一些公差来保证它正常工作。这些公差已经被调谐得适合米-千克- 秒(MKS)单位。尤其是, Box2D 被调谐得能良好地处理0.1到10米之间的移动物体。这意味着从罐头盒到公共汽车大小的对象都能良好地工作。静态的物体就算到50米都没有大问题。作为一个2D 物理引擎,如果能使用像素作为单位是很诱人的。很不幸,那将导致不良模拟,也可能会造成古怪的行为。一个200像素长的物体在 Box2D 看来就有45 层建筑那么大。想象下使用一个已调谐好用于模拟玩偶和木桶的引擎去模拟高楼大厦的运动。那并不有趣。注意Box2D 已被调谐至

13、 MKS 单位。移动物体的尺寸应该保持在大约 0.1 到 10 米之间。当你渲染场景和角色时, 可能要用到一些比例缩放系统。 Box2D 自带的 testbed 例子使用了OpenGL 的视口变换。最好把 Box2D 中的物体看作移动的广告板, 其上带着你的艺术创作。广告板在一个以米为单位的系统里运动,但你可以利用简单的比例因子把它转换为像素坐标。之后就可以使用这些像素坐标去确定你的精灵(sprites)的位置,等等。Box2D 里的角使用弧度制。物体的旋转角度以弧度方式存储,并可以无限增大。如角度变得太大,可考虑将角度进行规范化。(使用 b2Body:SetAngle)。1.8 工厂和定义内

14、存管理在 Box2D API 的设计中担当了一个中心角色。所以当你创建一个 b2Body 或一个 b2Joint 时, 你需要调用 b2World 的工厂函数(factory functions)。你不应以别的方式为这些类型分配内存。这些是创建函数:b2Body* b2World:CreateBody(constb2BodyDef* def)b2Joint* b2World:CreateJoint(constb2JointDef* def)在 libgdx 中对应于 World 类中相应方法:public Body createBody (BodyDef def)public Joint cr

15、eateJoint (JointDef def)这些是对应的摧毁函数:void b2World:DestroyBody(b2Body*body)void b2World:DestroyJoint(b2Joint*joint)在 libgdx 中对应于 World 类中相应方法:public void destroyBody (Body body)public void destroyJoint (Joint joint)当你创建物体或关节时, 需要提供定义 (definition)。这些定义包含了创建物体或关节时需要的所有信息。使用这样的方法,我们能够预防构造错误, 使函数参数的数量较少 ,提

16、供有意义的默认值,并减少访问子(accessor)的个数。fixture 必须有父 body, 要使用 b2Body 的工厂方法来创建及摧毁。b2Fixture* b2Body:CreateFixture(constb2FixtureDef* def)voidb2Body:DestroyFixture(b2Fixture* fixture)也有个简便方法直接用形状和密度来创建 fixtureb2Fixture* b2Body:CreateFixture(constb2Shape* shape, float32 density)在 libgdx 中对应于 Body 类中相应方法:public F

17、ixture createFixture (FixtureDef def)public void destroyJoint (Joint joint)工厂并不保留定义的引用, 你可以在栈上临时创建定义。1.9 用户数据b2Fixture, b2Body 和 b2Joint 类都允许你通过一个 void 指针来附加用户数据。当你测试 Box2D, 以及使得 Box2D 的数据结构跟自己的游戏引擎结合起来, 用 void 指针是较为方便的。举个典型的例子, 角色上有刚体 , 并在刚体中附加角色的指针 , 就构成了一个循环引用。如果你有角色(actor), 你就能得到刚体。如果你有刚体 ,你就能得到

18、角色。GameActor* actor =GameCreateActor();b2BodyDef bodyDef;bodyDef.userData = actor;actor-body =box2Dworld-CreateBody(在 libgdx 中对应于 Body 类中相应方法:public void setUserData (Object userData)一些需要用户数据的例子: 使用碰撞结果给角色施加伤害。 当玩家进入一个包围盒(axis-aligned box)时触发脚本事件 当 Box2D 通知关节就要摧毁时, 去访问某个游戏结构。记住,用户数据是可选的,并且能放入任何东西。然而

19、,你需要确保一致性。例如,如果你想在某个 body 中保存 actor 的指针,那你就应该在所有的 body 中都保存 actor 指针。不要在一个 body 中保存 actor 指针,却在另一个 body 中保存 foo 指针。将一个 actor 指针强制转成foo 指针,可能会导致程序崩溃。第02章 Hello Box2DBox2D 的发布包中有个 Hello World 程序。程序创建了一个大大的地面盒(ground box)和一个小小的动态盒(dynamic box)。盒子的位置随着时间的变化而变化。代码没有涉及到图形界面,你只能在控制台中看到文字输出这是个很好的例子, 展示了怎么使用

20、 Box2D。2.1 创建世界(Creating a World)每个 Box2D 程序开始时都会创建一个 b2World 对象。b2World 是物理枢纽(physics hub), 用于管理内存、对象和模拟。根据自己的实际情况, 你可以在栈, 堆或数据区中创建出world。创建 Box2D 的 world 很简单。首先, 我们要定义重力矢量,另外还要告诉 world 是否允许body 在静止时休眠。休眠中的 body 不需要任何模拟。b2Vec2 gravity(0.0f, -10.0f);bool doSleep = true;在 libgdx 中对应于以下代码:Vector2 grav

21、ity = new Vector2(0.0f, -10.0f);boolean doSleep = true;现在可以创建 world 对象了。注意,在这里我们是在栈中创建 world, 所以 world 不能离开它的作用域。b2World world(gravity, doSleep);在 libgdx 中对应于以下代码:world = new World(gravity, doSleep); 我们已经有了自己的物理世界, 开始向里面加东西了。2.2 创建地面盒(Creating a Ground Box)body 用以下步骤来创建:1. 用位置(position), 阻尼(damping)

22、等来定义 body2. 通过 world 对象来创建 body3. 用形状(shape), 摩擦(friction), 密度(density)等来定义 fixture4. 在 body 上来创建 fixture第一步,创建 ground body。我们需要一个 body 定义。在定义中,我们指定 ground body的初始位置。b2BodyDef groundBodyDef;groundBodyDef.position.Set(0.0f,-10.0f);在 libgdx 中对应于以下代码:BodyDef groundBodyDef = new BodyDef(); /声明物体定义 groun

23、dBodyDef.position.set(0.0f,-10.0f);第二步, 将 body 定义传給 world 对象, 创建 ground body。world 对象并不保留 body 定义的引用。ground body 是作为静态物体(static body)创建的。静态物体和其它静态物体之间并没有碰撞, 它们是固定的。当 body 的质量为零时, Box2D 就认为它是静态的。物体质量的默认值就为零, 所以它们默认就是静态的。b2Body* groundBody =world.CreateBody(在 libgdx 中对应于以下代码:Body groundBody = world.cr

24、eateBody(groundBodyDef); /通过 world 创建一个物体第三步, 创建地面多边形。我们用简便函数 SetAsBox 使得地面多边形构成一个盒子形状,盒子的中心点就是父 body 的原点。b2PolygonShape groundBox;groundBox.SetAsBox(50.0f, 10.0f);在 libgdx 中对应于以下代码:PolygonShape groundBox = new PolygonShape() ;groundBox.setAsBox(50.0f, 10.0f);SetAsBox 函数接收半个宽度和半个高度作为参数。因此在这种情况下,地面盒就

25、是100个单位宽(x 轴),20 个单位高(y 轴)。Box2D 已被调谐到使用米,千克和秒做单位。你可以认为长度单位就是米。当物体的大小跟真实世界一样时,Box2D 通常工作良好。例如,一个桶约1米高。由于浮点算法的局限性,使用 Box2D 模拟冰川或沙尘的运动并不是一个好主意。第四步, 我们创建 shape fixture, 以完成 ground body。这步中,我们有个简便方法。我们并不需要修改 fixture 默认的材质属性, 可以直接将形状传给 body 而不需要创建 fixture 的定义。随后的教程中, 我们将会看到如何使用 fixture 定义来定制材质属性。groundBo

26、dy-CreateFixture(在 libgdx 中对应于以下代码:groundBody.createFixture(groundBox, 1f); /将形状和密度赋给物体Box2D 并不保存 shape 的引用。它把数据复制到一个新的 b2Shape 对象中。注意,每个 fixture 都必须有一个父 body,即使 fixture 是静态的。然而,你可以把所有静态 fixture 都依附于单个静态 body 之上。之所以需要这个静态 body, 是为了保证 Box2D内部的代码更具一致性,以减少潜在的 bug 数量。可能你已经注意到, 多数 Box2D 类型都有 b2前缀。这是为了降低它

27、和你的代码之间名字冲突的机会。2.3 创建动态物体(Creating a Dynamic Body)现在我们已经有了一个地面 body,我们可以使用同样的方法来创建一个动态 body。除尺寸之外的主要区别是, 我们必须为动态 body 设置质量属性。首先我们用 CreateBody 创建 body。默认情况下,body 是静态的, 所以在构造时候应该设置 b2BodyType 使得 body 成为动态b2BodyDef bodyDef;bodyDef.type = b2_dynamicBody;bodyDef.position.Set(0.0f, 4.0f);b2Body* body =wor

28、ld.CreateBody(在 libgdx 中对应于以下代码:BodyDef bodyDef = new BodyDef(); / 声明物体定义bodyDef.position.set(0.0f, 4.0f);bodyDef.type=BodyType.DynamicBody;Body body = world.createBody(bodyDef); / 通过 world 创建一个物体注意如果你想 body 受力的影响而运动, 你必须将 body 的类型设为 b2_dynamicBody。然后,我们创建一个多边形 shapde, 并将它附加到 fixture 定义上。我们先创建一个 box

29、 shape:b2PolygonShape dynamicBox;dynamicBox.SetAsBox(1.0f, 1.0f);在 libgdx 中对应于以下代码:PolygonShape dynamicBox = new PolygonShape();dynamicBox.setAsBox(1.0f, 1.0f);接下来我们使用 box 创建一个 fixture 定义。注意, 我们把密度值设置为1,而密度值默认是0。并且,fixture 的摩擦系数设置为0.3 。b2FixtureDef fixtureDef;fixtureDef.shape = fixtureDef.density =

30、1.0f;fixtureDef.friction = 0.3f;在 libgdx 中对应于以下代码:FixtureDef fixtureDef = new FixtureDef();fixtureDef.shape =dynamicBox;fixtureDef.density = 1.0f;fixtureDef.friction = 0.3f;使用 fixture 定义, 我们现在就可以创建 fixture。这会自动更新 body 的质量。要是你喜欢, 你可以为 body 添加许多不同的 fixture。每个 fixture 都会增加物体的总质量。body-CreateFixture(在 li

31、bgdx 中对应于以下代码:body.createFixture(fixtureDef);这就是初始化过程。现在我们已经做好准备,可以开始模拟了。2.4 模拟(Box2D 的)世界我们已经初始化好了地面 box 和一个动态 box。该让牛顿来接手了。我们只有少数几个问题需要考虑。Box2D 使用了一个叫积分器(integrator)的数值算法。 积分器在离散的时间点上模拟连续的物理方程。 它与传统的游戏动画循环一同运行。我们需要为 Box2D 选取一个时间步。通常来说用于游戏的物理引擎需要至少 60Hz 的速度,也就是 1/60 的时间步。你可以使用更大的时间步,但是你必须更加小心地为你的世界

32、调整定义。我们也不喜欢时间步变化得太大,所以不要把时间步关联到帧频 (除非你真的必须这样做)。直截了当地,这个就是时间步:float32 timeStep = 1.0f / 60.0f;除积分器外,Box2D 代码还使用了约束求解器(constraint solver)。约束求解器用于解决模拟中的所有约束,一次一个。单个的约束会被完美的求解 ,然而当我们求解一个约束的时候 ,我们就会稍微耽误另一个。要得到良好的解,我们需要多次迭代所有约束。约束求解有两个阶段:速度、位置。在速度阶段,求解器会计算必要的冲量,使得物体正确运动。而在位置阶段,求解器会调整物体的位置,减少物体之间的重叠。每个阶段都有

33、自己的迭代计数。此外,如果误差已足够小的话,位置阶段的迭代可能会提前退出。对于速度和位置,建议的 Box2D 迭代次数都是10次。你可以按自己的喜好去调整这个数字,但要记得它是性能与精度之间的折中。更少的迭代会增加性能但降低精度,同样地,更多的迭代会降低性能但能提高模拟质量。对于这个简单示例,我们不需要多次迭代。这是我们选择的迭代次数。int32 velocityIterations = 6;int32 positionIterations = 2;时间步和迭代数是完全无关的。一个迭代并不是一个子步。一次迭代就是在时间步之中的单次遍历所有约束,你可以在单个时间步内多次遍历约束。现在我们可以开始

34、模拟循环了, 在你的游戏中, 模拟循环和游戏循环可以合并起来。每次游戏循环你都应该调用 b2World:Step, 通常调用一次就够了, 这取决于帧频以及物理时间步。步进后,你应当调用 b2World:ClearForces 清除你施加到 body 上的任何力。这个 Hello World 程序设计得非常简单, 它没有图形输出。代码会打印出动态 body 的位置以及旋转角, 有文字输出总比完全没有输出好。这就是模拟 1 秒钟内 60 个时间步的循环:for (int32 i = 0; i GetPosition();float32 angle =body-GetAngle();printf(“

35、%4.2f %4.2f%4.2fn“, position.x, position.y, angle);输出展示了动态 box 降落到地面的情况。你的输出看起来应当是这样:0.00 4.00 0.000.00 3.99 0.000.00 3.98 0.00.0.00 1.25 0.000.00 1.13 0.000.00 1.01 0.00在 libgdx 中对应于以下代码:public void render() float timeStep = Gdx.app.getGraphics().getDeltaTime();int velocityIterations = 6;int positi

36、onIterations = 2;world.step(timeStep,velocityIterations, positionIterations);world.clearForces();GL10 gl = Gdx.app.getGraphics().getGL10();gl.glClear(GL10.GL_COLOR_BUFFER_BIT);camera.update();camera.apply(gl);renderer.render(world, bined);最终运行效果类似下图,有一个非常快速的下降效果,每次重新运行程序才会出现:2.5 清理当 world 对象超出它的作用域,

37、 或通过指针将其 delete 时, 分配给 body, fixture, joint 使用的内存都会被释放。这能使你的生活变得更简单。然而,你应该将 body, fixture 或 joint 的指针都清零,因为它们已经无效了。在 libgdx 中对应于以下代码:public void dispose() renderer.dispose();world.dispose();renderer = null;world = null;2.6 Testbed 例子一旦你征服了 HelloWorld 例子 ,你应该开始看 Box2D 的 testbed 了。testbed 是个单元测试框架,也是个

38、演示环境, 这是它的一些特点: 可移动和缩放的摄像机 可用鼠标选中依附在动态物体上的形状 可扩展的测试集 通过图形界面选择测试,调整参数 ,以及设置调试绘图 暂停和单步模拟 文字渲染在 testbed 中有许多 Box2D 的测试用例,以及框架本身的实例。我鼓励你通过研究和修改它来学习 Box2D。注意:testbed 是使用 freeglut 和 GLUI 写成的,testbed 本身并不是 Box2D 库的一部分。Box2D 本身不知道如何渲染,就像 HelloWorld 例子一样,使用 Box2D 并不一定需要渲染。第03章 公共模块(Common)在 libgdx 仅需要关注3.3内存

39、管理部分:即 body, fixture 或 joint 对象的管理参照1.8工厂和定义中相应代码:3.1 关于公共模块包含了配置(Settings),内存管理(memory management)和矢量数学(vector math)3.2 配置头文件 b2Settings.h 包含: 类型 , 比如 int32和 float32 常数 分配器包装 (Allocation wrappers) 版本号 摩擦混合及恢复混合的函数类型Box2D 定义了不同的类型, 比如 float32, int8等, 方便确定结构的大小。常数Box2D 定义了一些常数, 都记录在 b2Settings.h 中。通常

40、你不需要调整这些常数。Box2D 的碰撞计算和物体模拟使用了浮点数学。考虑到有舍入方面的错误,所以要定义一些数值公差的,一些是绝对公差,另一些是相对公差。绝对公差使用 MKS 单位。分配器包装配置文件定义了 b2Alloc 和 b2Free, 用于大内存的分配。你可以让 b2Alloc 和 b2Free 再调用自己的内存管理系统(memory management system)。版本b2Version 结构保存了当前的版本信息,你可以在运行时(run-time) 查询.摩擦混合及恢复混合假如你的应用程序需要定制这些混合函数, 可以在配置文件中找到它们。3.3 内存管理Box2D 的许多设计都

41、是为了能快速有效地使用内存。在本节我将论述 Box2D 如何及为什么要这样分配内存。Box2D 倾向于分配大量的小型对象(50-300 字节左右) 。这样通过 malloc 或 new 在系统的堆(heap) 上 分配内存就太低效了 ,并且容易产生内存碎片。多数这些小型对象的生命期都很短暂,例如触点 (contact),可能只会维持几个时间步。所以我们需要为这些对象提供一个有效的堆分配器(heap allocator)。Box2D 的解决方案是使用小型对象分配器(SOA), 命名为 b2BlockAllocator。SOA 维护了一些不定尺寸并可扩展的内存池。当有内存分配请求时,SOA 会返回

42、一块大小最匹配的内存。当内存块释放之后, 它会被回收到池中。这些操作都十分快速, 只有很小的堆流量。因为 Box2D 使用了 SOA, 所以你永远也不应该去 new 或 malloc 一个 body, fixture 或joint。你只需分配一个 b2World,它为你提供了创建 body, fixture 和 joint 的工厂(factory) 。这使得 Box2D 可以使用 SOA 并且将赤裸的细节隐藏起来。同样绝对不要去 delete 或 free 一个 body, fixture 或 joint。当执行一个时间步的时候,Box2D 会需要一些临时的内存。为此 ,它使用了一个栈分配器来

43、消除单步堆分配, 这分配器命名为 b2StackAllocator。你不需要关心栈分配器,但对此有所了解还是不错的。3.4 数学Box2D 包含了一个简单,精细的矢量和矩阵模块,来满足 Box2D 内部和 API 接口的需要。所有的类都是公开的, 你可以在自己的应用程序中自由使用它们。数学库保持得尽量简单, 使得 Box2D 容易移植和维护。第04章 碰撞模块(Collision Module)4.1 关于碰撞模块包含了形状, 和操作形状的函数。该模块还包含了动态树(dynamic tree)和 broad-phase, 用于加快大型系统的碰撞处理速度。4.2 形状(Shapes)在 libg

44、dx 中对应于类:Shape形状描述了可相互碰撞的几何对象, 就算不进行物理模拟,也可独立使用。你可以在shape 上执行一些操作。b2Shape 是个基类, Box2D 的各种形状都实现了这个基类。此基类定义了几个函数: 判断一个点与形状是否有重叠 在形状上执行光线投射(ray cast) 计算形状的 AABB 计算形状的质量另外, 每个形状都有两成员变量 : 类型(type)和半径(radius) 。 对于多边形,半径也是有意义的, 下面会进行讨论。4.3 圆形(Circle Shapes)在 libgdx 中对应于类:CircleShape圆形有位置和半径。圆形是实心的,你没有办法使圆形

45、变成空心。但是,你可以使用多边形来创建一系列线段,让这些线段首尾相连,串成一串,就可以模拟出空心的圆形。b2CircleShape circle;circle.m_p.Set(1.0f, 2.0f, 3.0f);circle.m_radius = 0.5f;在 libgdx 中对应于类:Shape4.4 多边形(Polygon Shapes)Box2D 的多边形是实心的凸(Convex)多边形。在多边形内部任意选择两点,作一线段,如果所有的线段跟多边形的边都不相交,这个多边形就是凸多边形。多边形是实心的,不可能空心。但是,你可以使用两个点来创建多边形,这样就退化成线段。创建多边形时,使用的点必

46、须是逆时针排列(CCW)。我们必须很小心,逆时针是相对于右手坐标系统来说的,这坐标系下,Z 轴指向平面外面。有可能相对于你的屏幕,就变成顺时针了,这取决于你自己的坐标系统是怎么规定的。多边形的成员变量具有 public 访问权限,但是你也应该使用初始化函数来创建多边形。初始化函数会创建法向量(normal vectors)并检查参数的合法性。创建多边形时,你可以传递一个包含顶点的数组。数组大小最多是b2_maxPolygonVertices,这数值默认是8。这已足够描述大多数的凸多边形了。/ 按逆时针顺序定义一个三角形b2Vec2 vertices3;vertices0.Set(0.0f, 0

47、.0f);vertices1.Set(1.0f, 0.0f);vertices2.Set(0.0f, 1.0f);int32 count = 3;b2PolygonShape polygon;polygon.Set(vertices, count);多边形有一些定义好的初始化函数来创建箱(box)和边(edge,也就是线段)。void SetAsBox(float32 hx, float32hy);void SetAsBox(float32 hx, float32hy, const b2Vec2void SetAsEdge(const b2Vec2多边形从 b2Shape 中继承了半径。通过半

48、径,在多边形的周围创建了一个保护层 (skin)。堆叠的情况下,此保护层让多边形之间保持稍微分开。这使得可以在核心多边形上执行连续碰撞。(译注:这一段我不太明白,原文是Polygons inherit a radius from b2Shape. The radius creates a skin around the polygon. The skin is used in stacking scenarios to keep polygons slightly separated. This allows continuous collision to work against the core polygon.)4.5 形状的点测试(Shape Point Test)你可以测试一个点是否与形状有所重叠。使用这个函数, 需要提供一个形状的变换以及世界坐标上的一个点。b2Transfrom transform;transform.SetIdentity();b2Vec2 point(5.0f, 2.0f);bool hit =shape-TestPoint(transform, point);(译注: Box2D 中,形状附加在物体之上,它存储的数据是在物体的局部坐标系下定义的,而传进来要测试的点是在世界坐标系下,坐标系不同,就

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报