网上已经有个Box2D用户手册的翻译,但是基于v2.0.1,跟最新手册有很多不对应。
在这里决定将文档的全文再翻译出来,更准确的说是根据网上流传的v2.0.1版本,将最新文档重新整理一遍。
很多内容是直接复制自
Aman JIANG(江超宇)翻译的Box2D v2.0.1 用户手册
Box2D v2.1.0 用户手册
版权 © 2007-2010 Erin Catto
第01章 导言(Introduction)
第02章 Hello Box2D
第03章 公共模块(Common)
第04章 碰撞模块(Collision Module)
第05章 动态模块(Dynamics Module)
第06章 夹具(Fixtures)
第07章 物体(Bodies)
第08章 关节(Joints)
第09章 接触(Contacts)
第10章 世界(World Class)
第11章 杂项(Loose Ends)
第12章 调试绘图(Debug Drawing)
第13章 限制(Limitations)
第14章 参考(References)
Box2D是个二维刚体仿真库, 用于编写游戏。程序员可以使用它, 让游戏中的物体运动起来更真实, 让游戏世界更具交互性。以游戏的角度来看,物理引擎只是个程序性动画系统。(procedural animation)
(译注: 做动画常有两种方法, 一种是预先准备好动画所需的数据,比如图片,再一帧一帧地播放。另一种是以一定方法,动态计算出动画所需的数据,根据数据再进行绘图。
从这种角度看,预先准备的,可称为数据性动画,动态计算的可称为程序性动画。
这个区别,就类似以前我们做历史题和数学题,做历史题,记忆很重要,也就是答案需要预先准备好的。做数学题,方法就很重要,答案是需要用方法推导出来的。
Box2D就是用物理学的方法,推导出那游戏世界物体的位置,角度等数据。而Box2D也仅仅推导出数据,至于得到数据之后怎么处理就是程序员自己的事情了。)
Box2D用可移植的C++来写成,它定义的大部分类型都有b2前缀, 希望这能有效消除Box2D和你自己的游戏引擎之间的名字冲突。
在此手册中,我假定你已经熟悉了基本的物理概念,比如质量(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++程序设计, 还要学习怎么去编译, 连接和调试。网上有很多这方面的资料。
本手册涵盖了大多数Box2D的API,但并非每个方面都涉及到。Box2D自带了testbed例子, 鼓励你去看看, 以便了解更多。另外, Box2D的代码注释已被整理过, 符合Doxygen程序的格式要求, 所以很容易就可以创建一个有超链接的API文档。
如果你想反馈Box2D的任何内容,请在论坛里留下意见。这也是个交流讨论的好去处。
Box2D使用了Google code project进行问题跟踪。这是个跟踪问题的好方法, 保证你的反馈不会被淹没在论坛深处而无人理会。
反馈地址: http://code.google.com/p/box2d/
你的问题描述得越详细, 就越有可能得到修复。假如有个测试例子将问题重现, 就更好了。
Box2D中有一些基本对象, 这里我们先做一个简要的定义, 随后的文档会有更详细的描述。
2D几何对象, 比如圆形(circle)或多边形(polygon)。
十分坚硬的物质, 坚硬得像钻石,它上面任意两点之间的距离都保持不变。在后面的讨论中,我们用物体(body)来代替刚体。
fixture将形状绑定到物体之上, 并有一定的材质属性, 比如密度(density), 摩擦(friction)和恢复(restitution)。
(译注:一个物体和另一物体碰撞, 碰撞后速度和碰撞前速度的比值会保持不变,这比值就叫恢复系数。)
约束是个物理连接, 用于消除物体的自由度。在2D中, 物体有3个自由度(水平,垂直,旋转)。如果我们把一个物体钉在墙上(像钟摆那样), 那就把它约束到了墙上。这个时候,此物体就只能绕着钉子旋转, 所以这个约束消除了它2个自由度。
(译注:简单的说, 需要用几个参数来确定物体的空间状态, 这个物体就有几个自由度。在二维中,完全没有约束的条件下, 我们要确定物体的状态, 要有x坐标, y坐标, 旋转角这三个参数, 所以自由度为3。如果物体被钉在墙上, 只要有旋转角,就可以完全确定物体的状态,有了钉子这个约束,物体自由度就变成了1。)
一种特殊的约束, 设计的目的是为了防止刚体被穿透, 也用于模拟摩擦和恢复。接触约束不用你来创建, 它们会自动被Box2D生成。
关节就是种约束, 用于将两个或多个body固定到一起。Box2D支持不同的关节类型:转动(revolute),棱柱(prismatic),距离(distance)等。一些关节可以有限制(limits)和马达(motors)。
关节限制限定了一个关节的运动范围。例如人类的胳膊肘只能在某一角度范围内运动。
根据关节的自由度, 关节马达可以驱动关节所连接的物体。例如, 你可以使用一个马达来驱动一个肘的旋转。
一个物理世界就是各种, 刚体(bodies), 夹具(fixtures), 约束(constraints)相互作用的集合。 Box2D支持创建多个世界, 但这通常没有必要。
Box2D由三个模块组成:公共(Common)、碰撞(Collision)、和动态(Dynamics)。Common模块包括了内存分配、数学计算和配置。Collision模块定义了形状(shapes)、broad-phase检测和碰撞功能/查询(collision functions/queries)。最后,Dynamics模块提供对世界(world)、刚体(bodies)、夹具(fixtures)和关节(joint)的模拟。
(译注: Broad Phase是碰撞检测的一个子阶段, 将空间分割, 每个空间对应一个子树, 物体就放到树中, 不同子树内的物体不可能相交不用去计算, 在同一个子树由对应的算法再计算出接触点等信息。因为这是远距碰撞检测,就叫Broad Phase, 接下来还有Narrow Phase。)
Box2D使用浮点数, 所以必须使用一些公差来保证它正常工作。这些公差已经被调谐得适合米-千克-秒(MKS)单位。尤其是, Box2D被调谐得能良好地处理0.1到10米之间的移动物体。这意味着从罐头盒到公共汽车大小的对象都能良好地工作。静态的物体就算到50米都没有大问题。
作为一个2D物理引擎,如果能使用像素作为单位是很诱人的。很不幸,那将导致不良模拟,也可能会造成古怪的行为。一个200像素长的物体在Box2D看来就有45层建筑那么大。想象下使用一个已调谐好用于模拟玩偶和木桶的引擎去模拟高楼大厦的运动。那并不有趣。
注意
Box2D 已被调谐至 MKS 单位。移动物体的尺寸应该保持在大约 0.1 到 10 米之间。当你渲染场景和角色时, 可能要用到一些比例缩放系统。Box2D自带的testbed例子使用了OpenGL的视口变换。
最好把Box2D中的物体看作移动的广告板, 其上带着你的艺术创作。广告板在一个以米为单位的系统里运动,但你可以利用简单的比例因子把它转换为像素坐标。之后就可以使用这些像素坐标去确定你的精灵(sprites)的位置,等等。
Box2D里的角使用弧度制。物体的旋转角度以弧度方式存储,并可以无限增大。如角度变得太大,可考虑将角度进行规范化。(使用b2Body:SetAngle)。
内存管理在 Box2D API 的设计中担当了一个中心角色。所以当你创建一个 b2Body 或一个 b2Joint时, 你需要调用 b2World 的工厂函数(factory functions)。你不应以别的方式为这些类型分配内存。
这些是创建函数:
b2Body* b2World::CreateBody(constb2BodyDef* def)
b2Joint* b2World::CreateJoint(constb2JointDef* def)
这些是对应的摧毁函数:
void b2World::DestroyBody(b2Body*body)
void b2World::DestroyJoint(b2Joint*joint)
当你创建物体或关节时, 需要提供定义(definition)。这些定义包含了创建物体或关节时需要的所有信息。使用这样的方法,我们能够预防构造错误,使函数参数的数量较少,提供有意义的默认值,并减少访问子(accessor)的个数。
fixture必须有父body, 要使用b2Body的工厂方法来创建及摧毁。
b2Fixture* b2Body::CreateFixture(constb2FixtureDef* def)
voidb2Body::DestroyFixture(b2Fixture* fixture)
也有个简便方法直接用形状和密度来创建fixture
b2Fixture* b2Body::CreateFixture(constb2Shape* shape, float32 density)
工厂并不保留定义的引用, 你可以在栈上临时创建定义。
b2Fixture, b2Body 和 b2Joint 类都允许你通过一个 void 指针来附加用户数据。当你测试Box2D, 以及使得Box2D的数据结构跟自己的游戏引擎结合起来, 用void指针是较为方便的。
举个典型的例子, 角色上有刚体, 并在刚体中附加角色的指针, 就构成了一个循环引用。如果你有角色(actor), 你就能得到刚体。如果你有刚体,你就能得到角色。
GameActor* actor =GameCreateActor();
b2BodyDef bodyDef;
bodyDef.userData = actor;
actor->body =box2Dworld->CreateBody(&bodyDef);
一些需要用户数据的例子:
• 使用碰撞结果给角色施加伤害。
• 当玩家进入一个包围盒(axis-aligned box)时触发脚本事件
• 当Box2D通知关节就要摧毁时, 去访问某个游戏结构。
记住,用户数据是可选的,并且能放入任何东西。然而,你需要确保一致性。例如,如果你想在某个body中保存actor的指针,那你就应该在所有的body中都保存actor指针。不要在一个body中保存actor指针,却在另一个body中保存foo指针。将一个actor指针强制转成foo指针,可能会导致程序崩溃。