总览

Box2D是用于游戏的2D刚体仿真库。 程序员可以在游戏中使用它来使对象以逼真的方式移动,并使游戏世界更具交互性。 从游戏引擎的角度来看,物理引擎只是用于过程动画的系统。

Box2D用可移植的C ++编写。 引擎中定义的大多数类型都以b2前缀开头。 希望这足以避免名称与您的游戏引擎冲突。

先决条件

在本手册中,我假设您熟悉基本的物理概念,例如质量,力,转矩和脉冲。 如果没有,请先参考Google搜索和Wikipedia。

Box2D是在游戏开发者大会上作为物理教程的一部分而创建的。 您可以从box2d.org的下载部分获得这些教程。

由于Box2D是用C ++编写的,因此您应该具有C ++编程经验。 Box2D不应该是您的第一个C ++编程项目! 您应该熟悉编译,链接和调试。

警告:Box2D不应是您的第一个C ++项目。 在使用Box2D之前,请学习C ++编程,编译,链接和调试。 网上有很多资源。

范围

本手册涵盖了大部分Box2D API。 但是,并非涵盖所有方面。 请查看Box2D附带的测试台以了解更多信息。

本手册仅使用新版本进行更新。 Box2D的最新版本可能与本手册不同步。

反馈和错误

请在此处提交错误和功能请求:Box2D问题

如果您提供足够的详细信息,则可以帮助确保问题得到解决。 重现问题的测试平台示例是理想的。 您可以在本文档后面的内容中了解有关测试平台的信息。

还有一个Discord服务器和Box2D的subreddit。

核心概念

Box2D可处理几个基本概念和对象。我们在这里简要定义这些对象,并且在本文档后面将提供更多详细信息。

形状
形状是2D几何对象,例如圆形或多边形。

刚体
一块物质如此强大,以至于该物质上任何两个比特之间的距离都是恒定的。他们像钻石一样坚硬。在下面的讨论中,我们将使用body 代替rigid body。

固定装置
固定装置将形状绑定到身体,并增加了诸如密度,摩擦力和恢复性的材质属性。固定装置将一个形状放入碰撞系统(宽相)中,以便它可以与其他形状碰撞。

约束
约束是一种物理连接,它消除了物体的自由度。 2D物体具有3个自由度(两个平移坐标和一个旋转坐标)。如果我们将一个物体固定在墙上(如钟摆),则将其约束在墙壁上。此时,主体只能绕销旋转,因此约束已消除了2个自由度。

连接约束
一种特殊的约束,旨在防止刚体穿透并模拟摩擦和恢复原状。您不能创建连接约束,它们由Box2D自动创建。

关节
这是用于将两个或多个实体结合在一起的约束。 Box2D支持多种关节类型:旋转,棱柱形,距离等。某些关节可能具有limits 和motors。

关节约束
关节约束限制了关节的运动范围。例如,人的肘部仅允许一定范围的角度。

关节motor
关节motor根据关节的自由度来驱动连接体的运动。例如,您可以使用motor来驱动肘部的旋转。

世界
物理世界是相互作用的实体,固定装置和约束的集合。 Box2D支持创建多个世界,但这通常不是必需的或不希望的。

解算器
物理世界有一个求解器,该求解器用于延长时间并解决连接约束和关节约束。 Box2D求解器是一种高性能的迭代求解器,其顺序为N次,其中N是约束的数量。

连续碰撞
求解器使用不连续的时间步长按时间顺序推进实体。没有干预,这可能会导致穿透。

Overview_Box2D

Box2D包含用于处理穿透的专用算法。 首先,碰撞算法可以对两个物体的运动进行插值,以得出首次碰撞时间(TOI)。 其次,有一个分步求解器,可将物体移至它们的第一次碰撞,然后解决碰撞。

模块

Box2D由三个模块组成:“通用”,“碰撞”和“动力学”。 通用模块具有用于分配,数学和设置的代码。 碰撞模块定义形状,宽相和碰撞函数/查询。 最后,“动力学”模块提供了仿真世界,实体,夹具和关节。

Overview_Box2D_02

单位

Box2D使用浮点数,并且必须使用公差才能使Box2D表现良好。 这些公差已经过调整,可以与米-千克-秒(MKS)单位一起很好地工作。 特别是,Box2D已经过调整,可以在0.1到10米之间的移动形状下很好地工作。 因此,这意味着汤罐和公共汽车之间的物体应能正常工作。 静态形状可能长达50米而没有问题。

作为2D物理引擎,以像素为单位很诱人。 不幸的是,这将导致较差的仿真并可能产生怪异的行为。 Box2D可以将长度200像素的对象视为45层建筑物的大小。

警告:Box2D已针对MKS单位进行了调整。 保持移动物体的大小大约在0.1至10米之间。 渲染环境和角色时,需要使用一些缩放系统。 Box2D测试平台通过使用OpenGL视口转换来实现此目的。 请勿使用像素。

最好将Box2D实体视为在其上附加艺术品的移动广告牌。 广告牌可能以米为单位移动,但是您可以使用简单的比例因子将其转换为像素坐标。 然后,您可以使用这些像素坐标放置精灵等。您还可以考虑坐标轴的翻转。

要考虑的另一个限制是整个世界的大小。 如果您的世界单位变得大于2公里左右,那么精度损失会影响稳定性。

注意:Box2D在世界尺寸小于2公里的情况下效果最佳。 使用b2World :: ShiftOrigin支持更大的世界。

如果需要更大的游戏世界,请考虑使用b2World :: ShiftOrigin来使世界起源靠近您的玩家。 我建议使用网格线以及一些滞后来触发对ShiftOrigin的调用。 不应频繁进行此调用,因为它具有CPU开销。 在游戏单位和Box2D单位之间转换时,可能需要存储物理偏移。

Box2D使用弧度表示角度。 身体旋转以弧度存储,并且可能会无限增长。 如果角度的大小变得太大,请考虑将身体的角度归一化(使用b2Body :: SetTransform)。

注意:Box2D使用弧度而不是度。

更改长度单位

高级用户可以通过修改b2_lengthUnitsPerMeter来更改长度单位。 您可以通过定义B2_USER_SETTINGS并提供b2_user_settings.h来避免合并冲突。 有关详细信息,请参见文件b2_settings.h

工厂和定义

快速的内存管理在Box2D API的设计中起着核心作用。 因此,在创建b2Bodyb2Joint时,需要在b2World上调用工厂函数。 您永远不要尝试以其他方式分配这些类型。

b2Body* b2World::CreateBody(const b2BodyDef* def)
b2Joint* b2World::CreateJoint(const b2JointDef* def)

并且有相应的销毁功能:

void b2World::DestroyBody(b2Body* body)
void b2World::DestroyJoint(b2Joint* joint)

创建刚体或关节时,需要提供定义。 这些定义包含构建刚体或关节所需的所有信息。 通过使用这种方法,我们可以防止构造错误,使函数参数的数量保持较小,提供合理的默认值并减少访问器的数量。

由于固定装置(形状)必须是刚体的父类,因此它们是使用b2Body上的工厂方法创建和销毁的:

b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
void b2Body::DestroyFixture(b2Fixture* fixture)

还有直接从形状和密度创建固定装置的捷径。

b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float density)

工厂不保留对定义的引用。 因此,您可以在堆栈上创建定义,并将其保留在临时资源中。