关节,字面上理解是两块或者两块以上的骨头之间能活动的连接。这个解释也能套用在Box2D引擎当中的关节上,只不过骨头变成物体。在引擎当中,关节是将两个或者两个以上物体连接在一起的对象。物理世界中的关节有三个作用:
1.用于连接物体
2.它用于限制物体的移动。是一种约束
3.它本身是一个能够活动的对象
只要是由多个物体组成的游戏元素,基本都会需要关节。
关节的定义(JointDef)
与物体和框架一样,每种关节类型都有各自的定义,它们都派生自类b2JointDef。关节的定义主要是在创建关节时,提供基本的初始化数值。几乎所有的关节类型,都是用来连接两个不同的物体,其中一个物体有可能是静态的,另外一个则是动态的。也可能连接两个静态或者平台类型的物体,但这没有意义,只会增加运算消耗。
另外,任何一种关节类型都包含了一个用户数据的void指针。开发者可以用它来指定游戏元素。开发者可以用它来指定游戏元素。每一个关节对象还提供一个标记,用于防止关节相连的物体发生碰撞,如果读者有特殊的需求,希望一个关节上的两个物体也能够发生碰撞,则可以设置collideConnected布尔值来允许相连的物体之间发生碰撞。
很多关节定义需要提供一些几何数据,比如大多数的关节对象会需要一个锚点,来确定和物体固定连接得点。引擎会要求这些点要在局部坐标系中制定,这样的做的好处是就算当前物体的变化违反了关节约束,关节仍然可以被指定。
说明:在游戏保存或载入进度时,经常会发生物体违反关节约束的情况。
另外,还有些关节定义需要默认的物体之间的相对角度。这样是为了能够正确的设置旋转的约束。
关节的属性:
关节存在许多的类型。不过它们都是来自一个父类b2Joint。这就意味着它们会具有许多共同的属性。最明显的属性就是它们都会被称为什么什么类型的关节。在物理世界中,开发者需要使用关节工厂来创建关节对象。在我们介绍的物理世界中,还没有不是由工厂创建的对象。这是Box2D引擎管理对象的一个方式,关节作为物理世界中的一个类型,必然存在一些共同的属性。
在物理世界当中关节被创建之后直到摧毁,它通常都不会被访问。这主要与它的特点有关。它被用来作为物体之间的约束。开发者更习惯于操作代表着游戏元素的物体,但这并不表示关节对象不存在可访问的函数,在关节对象也包含了许多有用的数据,可以使得开发者创建出丰富的模拟效果。开发者可以在关节上得到约束的物体,锚点以及用户数据:
//得到物体
b2Body* GetBody1();
//得到锚点
b2Vec2 GetAnchor1();
//得到用户数据
void *GetUserData();
所有的关节都有反作用力和反扭矩,这个反作用力应用于物体2(body2)的锚点之上。开发者可以用反作用力来折断关节(break joints),或引发其他游戏事件。这些函数需要做一些物理计算,所以没有必要时,都不用去调用。
//得到反作用力
b2Vec2 GetReactionForce();
//得到反扭矩
float32 GetReactionTorque();
除了上述一个共有的函数以外,关节还有两个特殊的属性:
(1)限制(limit)存在于大多数关节类型当中。通过它,开发者可以控制连接物体运动的范围。
(2)马达(motor)也出现于许多的关节类型中。它用于以指定的速度驱动关节一直运动。开发者可以指定更大的力或扭矩来抵消这种运动,否则这个马达可以是永不停歇的。
关节马达与限制有许多不同的用途。开发者可以使用关节来控制位置,只要提供一个与目标距离成正比例的距离限制即可。比如两个绑在一起的球,就可以通过距离约束,使得它们具有一样的运动状态。另外它们还可以模拟关节摩擦,将关节速度置0,然后提供一个小的但有效的最大力或者扭矩,那么马达就会努力保持关节不动,直到负载变得过大。开发者可以设置一个马达来驱动物体关节旋转,比如推车上的四个轮子,就可以用马达来驱动。
距离关节(Distance Joint)
距离关节是为了确保两个物体之间的距离保持不变,同时两个物体可以任意运动和旋转。这里的距离保持不变,是指两个物体上关节锚点之间的距离不变。距离关节约束物体的使用方式很简单。当开发者制定一个距离关节时,两个物体必须已在所在的位置上。之后,指定世界坐标中两个锚点的位置,第一个锚点连接物体1,第二个锚点连接物体2,这两个锚点之间隐含了距离约束的长度,它们的距离必须固定不变。读者可以将其理解为用木板连接两个物体:
//距离关节定义
b2DistanceJointDef jointDef;
//初始化关节绑定的物体和锚点
jointDef.Initialize(myBody1,myBody2,worldAnchorOnBody1,worldAnchorOnBody2);
//开启物体之间的相互碰撞
jointDef.collideConnected = true;
距离关节可以是硬的,也可以是软的。
//距离关节
b2DistanceJointDef djd;
//使用柔软的距离限制,可以减少一些抖动,这也使得结构显得有点更流畅,就算悬挂系统
djd.dampingRatio = 2.0f;
djd.frequencyHz = 0.0f;
如果读者要使得距离关节有弹性,可以调用以下两个参数:
(1)频率(frequency):表示震动的快慢,单位为赫兹;
(2)阻尼率(dampingRatio)没有数据单位,数值在0-1之间,也可以更大。1是阻尼率的临界点,当阻尼率为1时,没有震动。
旋转关节(Revolute Joint)
旋转关节的作用是强制两个物体共享的一个锚点,这个锚点类似柳钉一样,将两个物体绑定在一起。旋转关节上的物体只有一个自由度,那就是物体的相对旋转。两个物体之间的角度差称为关节角。
b2RevoluteJointDef jointDef;
jointDef.Initialize(myBody1,myBody2,myBody1->GetWorldCenter());
之前说过绑定在旋转关节的两个物体是可以自由旋转的。在引擎中规定的逆时针旋转时,关节角为正值。并且和引擎中所有的角度一样,关节角也是弧度制的。在使用函数Initialize()创建旋转关节时,无论两个物体当前的角度怎样,旋转关节角都为0。
移动关节(Prismatic Joint)
移动关节是一个用来约束物体移动的关节,它允许两个物体沿指定轴相对移动,同时阻止物体相对旋转。和旋转关节类似,只不过旋转关节允许旋转,限制平移;而移动关节允许平移,限制旋转。相关代码:
//移动关节定义
b2PrismaticJointDef jointDef;
//关节锚点
b2Vec2 worldAxis(1.0f,0.0f);
//关节定义初始化
jointDef.Initialize(myBody1,myBody2,myBody1->GetWorldCenter(),worldAxis);
//角度限制
jointDef.lowerTranslation = -0.5f;
jointDef.upperTranslation = 2.5f;
另外,滑轮关节(Pulley Joint)、齿轮关节、鼠标关节、线性关节和焊接关节这里不再多说,如想了解请自行了解