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

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

举报
开通vip

Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注原文地址:http://blog.csdn.net/complex_ok/article/category/871440 网上已经有个Box2D用户手册的翻译,但是基于v2.0.1,跟最新手册有很多不对应。 在这里决定将文档的全文再翻译出来,更准确的说是根据网上流传的v2.0.1版本,将最新文档重新整理一遍。 很多内容是直接复制自 Box2D v2.0.1 用户手册 原文:Box2D v2.0.2 User Manual 译者:Aman JIANG(江超宇) Box2D v2.1.0 用户手册 版权...

Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注
原文地址:http://blog.csdn.net/complex_ok/article/category/871440 网上已经有个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是个二维刚体仿真库, 用于编写游戏。程序员可以使用它, 让游戏中的物体运动起来更真实, 让游戏世界更具交互性。以游戏的角度来看,物理引擎只是个程序性动画系统。(procedural animation) (译注: 做动画常有两种方法, 一种是预先准备好动画所需的数据,比如图片,再一帧一帧地播放。另一种是以一定方法,动态计算出动画所需的数据,根据数据再进行绘图。 从这种角度看,预先准备的,可称为数据性动画,动态计算的可称为程序性动画。 这个区别,就类似以前我们做历史题和数学题,做历史题,记忆很重要,也就是答案需要预先准备好的。做数学题,方法就很重要,答案是需要用方法推导出来的。 Box2D就是用物理学的方法,推导出那游戏世界物体的位置,角度等数据。而Box2D也仅仅推导出数据,至于得到数据之后怎么处理就是程序员自己的事情了。) Box2D用可移植的C++来写成,它定义的大部分类型都有b2前缀, 希望这能有效消除Box2D和你自己的游戏引擎之间的名字冲突。 1.2 先备条件(Prerequisites) 在此手册中,我假定你已经熟悉了基本的物理概念,比如质量(mass),力(force),扭矩(torque)和冲量(impulses)。如果没有, 建议读一下Chris Hecker和David Baraff (google 这些名字)的教程, 你不需要理解得非常细致, 只需很好地了解一些基本概念, 帮助你使用Box2D。 Wikipedia也是个很好的地方,去获取物理和数学知识。Wikipedia的内容经过了精心的整理,在某些方面可能比google更有用。 在Game Developer Conference上, Box2D是作为物理教程的一部分而创建的。你可以从box2d.org的下载区得到这些教程。 Box2D是使用C++写成的, 因此也假定你具备C++编程经验。Box2D不应该是你的第一个C++程序项目。你应该能熟练地编译,链接和调试。 注意 Box2D不应该是你的第一个C++项目。在使用Box2D之前, 请先学习C++程序设计, 还要学习怎么去编译, 连接和调试。网上有很多这方面的资料。 1.3 关于本手册 本手册涵盖了大多数Box2D的API,但并非每个方面都涉及到。Box2D自带了testbed例子, 鼓励你去看看, 以便了解更多。另外, Box2D的代码注释已被整理过, 符合Doxygen程序的格式要求, 所以很容易就可以创建一个有超链接的API文档。 1.4 反馈及错误报告 如果你想反馈Box2D的任何内容,请在论坛里留下意见。这也是个交流讨论的好去处。 Box2D使用了Google code project进行问题跟踪。这是个跟踪问题的好方法, 保证你的反馈不会被淹没在论坛深处而无人理会。 反馈地址: http://code.google.com/p/box2d/ 你的问题描述得越详细, 就越有可能得到修复。假如有个测试例子将问题重现, 就更好了。 1.5 核心概念(Core Concepts) Box2D中有一些基本对象, 这里我们先做一个简要的定义, 随后的文档会有更详细的描述。 形状(shape) 2D几何对象, 比如圆形(circle)或多边形(polygon)。 刚体(rigid body) 十分坚硬的物质, 坚硬得像钻石,它上面任意两点之间的距离都保持不变。在后面的讨论中,我们用物体(body)来代替刚体。 夹具(fixture) fixture将形状绑定到物体之上, 并有一定的材质属性, 比如密度(density), 摩擦(friction)和恢复(restitution)。 (译注:一个物体和另一物体碰撞, 碰撞后速度和碰撞前速度的比值会保持不变,这比值就叫恢复系数。) 约束(constraint) 约束是个物理连接, 用于消除物体的自由度。在2D中, 物体有3个自由度(水平,垂直,旋转)。如果我们把一个物体钉在墙上(像钟摆那样), 那就把它约束到了墙上。这个时候,此物体就只能绕着钉子旋转, 所以这个约束消除了它2个自由度。 (译注:简单的说, 需要用几个参数来确定物体的空间状态, 这个物体就有几个自由度。在二维中,完全没有约束的条件下, 我们要确定物体的状态, 要有x坐标, y坐标, 旋转角这三个参数, 所以自由度为3。如果物体被钉在墙上, 只要有旋转角,就可以完全确定物体的状态,有了钉子这个约束,物体自由度就变成了1。) 接触约束(contact constraint) 一种特殊的约束, 设计的目的是为了防止刚体被穿透, 也用于模拟摩擦和恢复。接触约束不用你来创建, 它们会自动被Box2D生成。 关节(joint) 关节就是种约束, 用于将两个或多个body固定到一起。Box2D支持不同的关节类型:转动(revolute),棱柱(prismatic),距离(distance)等。一些关节可以有限制(limits)和马达(motors)。 关节限制(joint limit) 关节限制限定了一个关节的运动范围。例如人类的胳膊肘只能在某一角度范围内运动。 关节马达(joint motor) 根据关节的自由度, 关节马达可以驱动关节所连接的物体。例如, 你可以使用一个马达来驱动一个肘的旋转。 世界(world) 一个物理世界就是各种, 刚体(bodies), 夹具(fixtures), 约束(constraints)相互作用的集合。 Box2D支持创建多个世界, 但这通常没有必要。 libgdx核心概念应用到游戏之初步理解: 1、 利用world模拟创建游戏的物理世界; 2、 利用body创建各种通用物体; 3、 利用fixtures给予通用物体基本属性(密度、摩擦力)以仿真各种真实物体; 4、 利用joint将两个或多个物体(body)关联到一起,创建组合一起运动的物体,如旋转机器人,类似使用组合多个图片实现动画效果的物体。 5、 当游戏中各种物体状态发生改变,导致出现碰撞时,contact及contact constraint 就出现了,contact用来 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示两个物体之间出现了碰撞,contact constraint用于限制碰撞的影响范围。 6、 通常游戏需要对物体的碰撞进行处理,以实现游戏效果,此时需要利用Contact Listener相应的接口消除部分物体的碰撞、记录发生碰撞的物体状态以立即实现游戏效果。 1.6 模块(Modules) Box2D由三个模块组成:公共(Common)、碰撞(Collision)、和动态(Dynamics)。Common模块包括了内存分配、数学计算和配置。Collision模块定义了形状(shapes)、broad-phase检测和碰撞功能/查询(collision functions/queries)。最后,Dynamics模块提供对世界(world)、刚体(bodies)、夹具(fixtures)和关节(joint)的模拟。 (译注: Broad Phase是碰撞检测的一个子阶段, 将空间分割, 每个空间对应一个子树, 物体就放到树中, 不同子树内的物体不可能相交不用去计算, 在同一个子树由对应的算法再计算出接触点等信息。因为这是远距碰撞检测,就叫Broad Phase, 接下来还有Narrow Phase。) 1.7 单位 Box2D使用浮点数, 所以必须使用一些公差来保证它正常工作。这些公差已经被调谐得适合米-千克-秒(MKS)单位。尤其是, Box2D被调谐得能良好地处理0.1到10米之间的移动物体。这意味着从罐头盒到公共汽车大小的对象都能良好地工作。静态的物体就算到50米都没有大问题。 作为一个2D物理引擎,如果能使用像素作为单位是很诱人的。很不幸,那将导致不良模拟,也可能会造成古怪的行为。一个200像素长的物体在Box2D看来就有45层建筑那么大。想象下使用一个已调谐好用于模拟玩偶和木桶的引擎去模拟高楼大厦的运动。那并不有趣。 注意 Box2D 已被调谐至 MKS 单位。移动物体的尺寸应该保持在大约 0.1 到 10 米之间。当你渲染场景和角色时, 可能要用到一些比例缩放系统。Box2D自带的testbed例子使用了OpenGL的视口变换。 最好把Box2D中的物体看作移动的广告板, 其上带着你的艺术创作。广告板在一个以米为单位的系统里运动,但你可以利用简单的比例因子把它转换为像素坐标。之后就可以使用这些像素坐标去确定你的精灵(sprites)的位置,等等。 Box2D里的角使用弧度制。物体的旋转角度以弧度方式存储,并可以无限增大。如角度变得太大,可考虑将角度进行 规范 编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载 化。(使用b2Body:SetAngle)。 1.8 工厂和定义 内存管理在 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 createJoint (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)。这些定义包含了创建物体或关节时需要的所有信息。使用这样的方法,我们能够预防构造错误,使函数参数的数量较少,提供有意义的默认值,并减少访问子(accessor)的个数。 fixture必须有父body, 要使用b2Body的工厂方法来创建及摧毁。 b2Fixture* b2Body::CreateFixture(constb2FixtureDef* def) voidb2Body::DestroyFixture(b2Fixture* fixture) 也有个简便方法直接用形状和密度来创建fixture b2Fixture* b2Body::CreateFixture(constb2Shape* shape, float32 density) 在libgdx中对应于Body类中相应方法: public Fixture createFixture (FixtureDef def) public void destroyJoint (Joint joint) 工厂并不保留定义的引用, 你可以在栈上临时创建定义。 1.9 用户数据 b2Fixture, b2Body 和 b2Joint 类都允许你通过一个 void 指针来附加用户数据。当你测试Box2D, 以及使得Box2D的数据结构跟自己的游戏引擎结合起来, 用void指针是较为方便的。 举个典型的例子, 角色上有刚体, 并在刚体中附加角色的指针, 就构成了一个循环引用。如果你有角色(actor), 你就能得到刚体。如果你有刚体,你就能得到角色。 GameActor* actor =GameCreateActor(); b2BodyDef bodyDef; bodyDef.userData = actor; actor->body =box2Dworld->CreateBody(&bodyDef); 在libgdx中对应于Body类中相应方法: public void setUserData (Object userData) 一些需要用户数据的例子: • 使用碰撞结果给角色施加伤害。 • 当玩家进入一个包围盒(axis-aligned box)时触发脚本事件 • 当Box2D通知关节就要摧毁时, 去访问某个游戏结构。 记住,用户数据是可选的,并且能放入任何东西。然而,你需要确保一致性。例如,如果你想在某个body中保存actor的指针,那你就应该在所有的body中都保存actor指针。不要在一个body中保存actor指针,却在另一个body中保存foo指针。将一个actor指针强制转成foo指针,可能会导致程序崩溃。 第02章 Hello Box2D Box2D的发布包中有个Hello World程序。程序创建了一个大大的地面盒(ground box)和一个小小的动态盒(dynamic box)。盒子的位置随着时间的变化而变化。代码没有涉及到图形界面,你只能在控制台中看到文字输出 这是个很好的例子, 展示了怎么使用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 gravity = 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)等来定义body 2. 通过world对象来创建body 3. 用形状(shape), 摩擦(friction), 密度(density)等来定义fixture 4. 在body上来创建fixture 第一步,创建ground body。我们需要一个body定义。在定义中,我们指定ground body的初始位置。 b2BodyDef groundBodyDef; groundBodyDef.position.Set(0.0f,-10.0f); 在libgdx中对应于以下代码: BodyDef groundBodyDef = new BodyDef(); //声明物体定义 groundBodyDef.position.set(0.0f,-10.0f); 第二步, 将body定义传給world对象, 创建ground body。world对象并不保留body定义的引用。ground body是作为静态物体(static body)创建的。静态物体和其它静态物体之间并没有碰撞, 它们是固定的。当body的质量为零时, Box2D就认为它是静态的。物体质量的默认值就为零, 所以它们默认就是静态的。 b2Body* groundBody =world.CreateBody(&groundBodyDef); 在libgdx中对应于以下代码: Body groundBody = world.createBody(groundBodyDef); //通过world创建一个物体 第三步, 创建地面多边形。我们用简便函数SetAsBox使得地面多边形构成一个盒子形状,盒子的中心点就是父body的原点。 b2PolygonShape groundBox; groundBox.SetAsBox(50.0f, 10.0f); 在libgdx中对应于以下代码: PolygonShape groundBox = new PolygonShape() ; groundBox.setAsBox(50.0f, 10.0f); SetAsBox函数接收半个宽度和半个高度作为参数。因此在这种情况下,地面盒就是100个单位宽(x轴),20个单位高(y轴)。Box2D已被调谐到使用米,千克和秒做单位。你可以认为长度单位就是米。当物体的大小跟真实世界一样时,Box2D通常工作良好。例如,一个桶约1米高。由于浮点算法的局限性,使用Box2D模拟冰川或沙尘的运动并不是一个好主意。 第四步, 我们创建shape fixture, 以完成ground body。这步中,我们有个简便方法。我们并不需要修改fixture默认的材质属性, 可以直接将形状传给body而不需要创建fixture的定义。随后的教程中, 我们将会看到如何使用fixture定义来定制材质属性。 groundBody->CreateFixture(&groundBox); 在libgdx中对应于以下代码: groundBody.createFixture(groundBox, 1f); //将形状和密度赋给物体 Box2D并不保存shape的引用。它把数据复制到一个新的b2Shape对象中。 注意,每个fixture都必须有一个父body,即使fixture是静态的。然而,你可以把所有静态fixture都依附于单个静态body之上。之所以需要这个静态body, 是为了保证Box2D内部的代码更具一致性,以减少潜在的bug数量。 可能你已经注意到, 多数Box2D类型都有b2前缀。这是为了降低它和你的代码之间名字冲突的机会。 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 =world.CreateBody(&bodyDef); 在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 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 = &dynamicBox; fixtureDef.density = 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(&fixtureDef); 在libgdx中对应于以下代码: body.createFixture(fixtureDef); 这就是初始化过程。现在我们已经做好准备,可以开始模拟了。 2.4 模拟(Box2D的)世界 我们已经初始化好了地面box和一个动态box。该让牛顿来接手了。我们只有少数几个问题需要考虑。 Box2D使用了一个叫积分器(integrator)的数值算法。 积分器在离散的时间点上模拟连续的物理方程。 它与传统的游戏动画循环一同运行。我们需要为Box2D选取一个时间步。通常来说用于游戏的物理引擎需要至少 60Hz 的速度,也就是 1/60 的时间步。你可以使用更大的时间步,但是你必须更加小心地为你的世界调整定义。我们也不喜欢时间步变化得太大,所以不要把时间步关联到帧频(除非你真的必须这样做)。直截了当地,这个就是时间步: float32 timeStep = 1.0f / 60.0f; 除积分器外,Box2D代码还使用了约束求解器(constraint solver)。约束求解器用于解决模拟中的所有约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另一个。要得到良好的解,我们需要多次迭代所有约束。 约束求解有两个阶段:速度、位置。在速度阶段,求解器会计算必要的冲量,使得物体正确运动。而在位置阶段,求解器会调整物体的位置,减少物体之间的重叠。每个阶段都有自己的迭代计数。此外,如果误差已足够小的话,位置阶段的迭代可能会提前退出。 对于速度和位置,建议的Box2D迭代次数都是10次。你可以按自己的喜好去调整这个数字,但要记得它是性能与精度之间的折中。更少的迭代会增加性能但降低精度,同样地,更多的迭代会降低性能但能提高模拟质量。对于这个简单示例,我们不需要多次迭代。这是我们选择的迭代次数。 int32 velocityIterations = 6; int32 positionIterations = 2; 时间步和迭代数是完全无关的。一个迭代并不是一个子步。一次迭代就是在时间步之中的单次遍历所有约束,你可以在单个时间步内多次遍历约束。 现在我们可以开始模拟循环了, 在你的游戏中, 模拟循环和游戏循环可以合并起来。每次游戏循环你都应该调用b2World::Step, 通常调用一次就够了, 这取决于帧频以及物理时间步。步进后,你应当调用b2World::ClearForces清除你施加到body上的任何力。 这个Hello World程序设计得非常简单, 它没有图形输出。代码会打印出动态body的位置以及旋转角, 有文字输出总比完全没有输出好。这就是模拟 1 秒钟内 60 个时间步的循环: for (int32 i = 0; i < 60; ++i) { world.Step(timeStep,velocityIterations, positionIterations); world.ClearForces(); b2Vec2 position =body->GetPosition(); float32 angle =body->GetAngle(); printf("%4.2f %4.2f%4.2f\n", position.x, position.y, angle); } 输出展示了动态box降落到地面的情况。你的输出看起来应当是这样: 0.00 4.00 0.00 0.00 3.99 0.00 0.00 3.98 0.00 ... 0.00 1.25 0.00 0.00 1.13 0.00 0.00 1.01 0.00 在libgdx中对应于以下代码: public void render() { float timeStep = Gdx.app.getGraphics().getDeltaTime(); int velocityIterations = 6; int positionIterations = 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, camera.combined); } 最终运行效果类似下图,有一个非常快速的下降效果,每次重新运行程序才会出现: 2.5 清理 当world对象超出它的作用域,或通过指针将其 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 是个单元测试框架,也是个演示环境, 这是它的一些特点: • 可移动和缩放的摄像机 • 可用鼠标选中依附在动态物体上的形状 • 可扩展的测试集 • 通过图形界面选择测试,调整参数,以及设置调试绘图 • 暂停和单步模拟 • 文字渲染 在 testbed 中有许多 Box2D 的测试用例,以及框架本身的实例。我鼓励你通过研究和修改它来学习 Box2D。 注意:testbed 是使用 freeglut 和 GLUI 写成的,testbed 本身并不是 Box2D 库的一部分。Box2D本身不知道如何渲染,就像 HelloWorld 例子一样,使用 Box2D 并不一定需要渲染。 第03章 公共模块(Common) 在libgdx仅需要关注3.3内存管理部分:即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中。通常你不需要调整这些常数。 Box2D的碰撞计算和物体模拟使用了浮点数学。考虑到有舍入方面的错误,所以要定义一些数值公差的,一些是绝对公差,另一些是相对公差。绝对公差使用MKS单位。 分配器包装 配置文件定义了b2Alloc和b2Free, 用于大内存的分配。你可以让b2Alloc和b2Free再调用自己的内存管理系统(memory management system)。 版本 b2Version结构保存了当前的版本信息,你可以在运行时(run-time)查询. 摩擦混合及恢复混合 假如你的应用程序需要定制这些混合函数, 可以在配置文件中找到它们。 3.3 内存管理 Box2D 的许多设计都是为了能快速有效地使用内存。在本节我将论述 Box2D 如何及为什么要这样分配内存。 Box2D 倾向于分配大量的小型对象(50-300 字节左右)。这样通过 malloc 或 new 在系统的堆(heap)上 分配内存就太低效了,并且容易产生内存碎片。多数这些小型对象的生命期都很短暂,例如触点 (contact),可能只会维持几个时间步。所以我们需要为这些对象提供一个有效的堆分配器(heap allocator)。 Box2D的解决方案是使用小型对象分配器(SOA), 命名为b2BlockAllocator。SOA维护了一些不定尺寸并可扩展的内存池。当有内存分配请求时,SOA 会返回一块大小最匹配的内存。当内存块释放之后, 它会被回收到池中。这些操作都十分快速,只有很小的堆流量。 因为 Box2D 使用了SOA, 所以你永远也不应该去 new 或 malloc 一个body, fixture或joint。你只需分配一个 b2World,它为你提供了创建body, fixture和joint的工厂(factory)。这使得Box2D可以使用 SOA 并且将赤裸的细节隐藏起来。同样绝对不要去 delete 或 free 一个body, fixture或joint。 当执行一个时间步的时候,Box2D 会需要一些临时的内存。为此,它使用了一个栈分配器来消除单步堆分配, 这分配器命名为b2StackAllocator。你不需要关心栈分配器,但对此有所了解还是不错的。 3.4 数学 Box2D包含了一个简单,精细的矢量和矩阵模块,来满足Box2D内部和API接口的需要。所有的类都是公开的, 你可以在自己的应用程序中自由使用它们。 数学库保持得尽量简单, 使得Box2D容易移植和维护。 第04章 碰撞模块(Collision Module) 4.1 关于 碰撞模块包含了形状, 和操作形状的函数。该模块还包含了动态树(dynamic tree)和broad-phase, 用于加快大型系统的碰撞处理速度。 4.2 形状(Shapes) 在libgdx中对应于类:Shape 形状描述了可相互碰撞的几何对象, 就算不进行物理模拟,也可独立使用。你可以在shape上执行一些操作。 b2Shape是个基类, Box2D的各种形状都实现了这个基类。此基类定义了几个函数: • 判断一个点与形状是否有重叠 • 在形状上执行光线投射(ray cast) • 计算形状的AABB • 计算形状的质量 另外, 每个形状都有两成员变量: 类型(type)和半径(radius)。 对于多边形,半径也是有意义的, 下面会进行讨论。 4.3 圆形(Circle Shapes) 在libgdx中对应于类:CircleShape 圆形有位置和半径。 圆形是实心的,你没有办法使圆形变成空心。但是,你可以使用多边形来创建一系列线段,让这些线段首尾相连,串成一串,就可以模拟出空心的圆形。 b2CircleShape circle; circle.m_p.Set(1.0f, 2.0f, 3.0f); circle.m_radius = 0.5f; 在libgdx中对应于类:Shape 4.4 多边形(Polygon Shapes) Box2D的多边形是实心的凸(Convex)多边形。在多边形内部任意选择两点,作一线段,如果所有的线段跟多边形的边都不相交,这个多边形就是凸多边形。多边形是实心的,不可能空心。但是,你可以使用两个点来创建多边形,这样就退化成线段。 创建多边形时,使用的点必须是逆时针排列(CCW)。我们必须很小心,逆时针是相对于右手坐标系统来说的,这坐标系下,Z轴指向平面外面。有可能相对于你的屏幕,就变成顺时针了,这取决于你自己的坐标系统是怎么规定的。 多边形的成员变量具有public访问权限,但是你也应该使用初始化函数来创建多边形。初始化函数会创建法向量(normal vectors)并检查参数的合法性。 创建多边形时,你可以传递一个包含顶点的数组。数组大小最多是b2_maxPolygonVertices,这数值默认是8。这已足够描述大多数的凸多边形了。 // 按逆时针顺序定义一个三角形 b2Vec2 vertices[3]; vertices[0].Set(0.0f, 0.0f); vertices[1].Set(1.0f, 0.0f); vertices[2].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 b2Vec2& center, float32 angle); void SetAsEdge(const b2Vec2& v1,const b2Vec2& v2); 多边形从b2Shape中继承了半径。通过半径,在多边形的周围创建了一个保护层(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中,形状附加在物体之上,它存储的数据是在物体的局部坐标系下定义的,而传进来要测试的点是在世界坐标系下,坐标系不同,就没有办法比较。这个transform用于将形状从局部坐标系转到世界坐标系,之后才可进行比较。而transform的逆转换就是将世界坐标系转到局部坐标系。故要实现这个函数,也可以先求逆转换,将传过来的点转到局部坐标系,这同样可以进行比较,要看哪一个方便。 看Box2D的源码,它实现b2CircleShape::TestPoint时,是将圆心转成世界坐标系,再比较。而b2PolygonShape::TestPoint,是将传进来的点先转成局部坐标再比较。因为转成世界坐标,多边形要同时转换多个点,而圆形就只转换圆心。 使用局部坐标系,不管物体怎么移动,旋转及缩放,改变的只是这个转换矩阵,形状存储的点不用修改,这样就很方便了。下面文档中,你可以看到形状的很多函数,都会传进一个转换,道理是一样的。) 4.6 形状的光线投射(Shape Ray Cast) 你可以用光线射向形状,得到它们之间的交点和法向量。如果在形状内部开始投射,就当成没有交点,返回false。 b2Transfrom transform; transform.SetIdentity(); b2RayCastInput input; input.p1.Set(0.0f, 0.0f); input.p2.Set(1.0f, 0.0f); input.maxFraction = 1.0f; b2RayCastOutput output; bool hit =shape->RayCast(&output, input, transform); if (hit) { b2Vec2 hitPoint = input.p1 +output.fraction * (input.p2 - input.p1); } (译注: 这里说的光线指几何中的射线。 看看b2RayCastInput的定义,除指定了两个点p1, p2外,还有个maxFraction。这个maxFraction是什么意思呢? 我们知道,两点决定一个直线,在数学上知道了两点,再定义直线上的其它点,常使用参数方程。也就是定义 P(fraction) = p1 + fraction * (p2 - p1)。当fraction为0时,就代表p1, 当fraction=1时,就代表p2。这样的定义下,两点之间的线段就是参数从0到1之间变化。参数小于0,表示反向的点,大于1就表示正向超出线段的点。maxFraction就表示要测试的点对应的参数是在[0, maxFraction]内。b2RayCastOutput也有个fraction,意思是一样的。 数学上很喜欢将一些变量归结成0到1之间变化,这叫做规范化。处理问题的常用手段是用某个变换(这里说的变换是广义的)将变量归结成0到1之间,再在规范化之下计算, 之后再用个反变换得到原问题的答案。上面说的直线参数化,可以看成规范化的一种。那为什么要规范化呢?因为这样计算起来方便。那为什么会方便呢?我就答不出来了。Box2D中凡是涉及到向量的,那个单词fraction应该都是上面说的意思。) 4.7 对等函数(Bilateral Functions) 碰撞模块含有对等函数,要传递两个形状,计算出结果。包括: • 接触manifolds • 距离 • 撞击时间 4.8 接触Manifolds (译注: 我不知道Manifold应该翻译成什么,我猜Manifold指有相同属性的一堆东西,可以理解成集合,但翻译成集合又不好。故直接保留英文) Box2D有些函数用来计算重合形状之间的接触点。考虑一下圆与圆,圆与多边形的碰撞,我们只会得到一个接触点和一个向量。多边形与多边形的碰撞,我们可以得到两个接触点。这些接触点都具有相同的法向量,所以Box2D就将它们归成一组,构成manifold结构。接触求解器进一步处理这结构,以改善物体堆叠在一起时,系统的稳定性。 通常你不需要直接计算接触manifold, 但你可能会希望使用这模拟过程中已处理好的结果。 b2Manifold结构含有一个法向量和最多两个的接触点。向量和接触点都是相对于局部坐标系。为方便接触求解器处理,每个接触点都存储了法向冲量和切向(摩擦)冲量。 b2WorldManifold结构可以用来生成世界坐标下的接触向量和点。你需要提供b2Manifold结构和形状的转换及半径。 b2WorldManifold worldManifold; worldManifold.Initialize(&manifold,transformA, shapeA.m_radius, transformB,shapeB.m_radius); for (int32 i = 0; i
本文档为【Box2D+v2.1.0用户手册中文翻译_增加libgdx中box2d使用批注】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_465473
暂无简介~
格式:doc
大小:340KB
软件:Word
页数:60
分类:互联网
上传时间:2012-07-14
浏览量:172