第四章主要介绍关节(joint)。

# 关节(joint)

# 关于

关节的作用是把物体约束到世界,或约束到其它物体上。在游戏中的典型例子是木偶,跷跷板和滑轮。关节可以用许多种不同的方法结合起来,创造出有趣的运动。

有些关节提供了限制(limit),以便你控制运动范围。有些关节还提供了马达(motor),它可以以指定的速度驱动关节,直到你指定了更大的力或扭矩。

关节马达有许多不同的用途。你可以使用关节来控制位置,只要提供一个与目标之距离成正比例的关节速度即可。你还可以模拟关节摩擦:将关节速度置零,并且提供一个小的、但有效的最大力或扭矩; 那么马达就会努力保持关节不动,直到负载变得过大。

# 关节定义

各种关节类型都派生自 b2JointDef。所有关节都连接两个不同的物体,可能其中一个是静态物体。如果你想浪费内存的话,那就创建一个连接两个静态物体的关节。

你可以为任何一种关节指定用户数据。你还可以提供一个标记,用于预防相连的物体发生碰撞。实际上,这是默认行为,你可以设置 collideConnected 布尔值来允许相连的物体碰撞。

很多关节定义需要你提供一些几何数据。一个关节常常需要一个锚点(anchor point)来定义,这是固 定于相接物体中的点。在 Box2D 中这些点需要在局部坐标系中指定,这样,即便当前物体的变化违反了关节约束,关节还是可以被指定——在游戏存取进度时这经常会发生。另外,有些关节定义需要默认的物体之间的相对角度。这样才能通过关节限制或固定的相对角来正确地约束旋转。

初始化几何数据可能有些乏味。所以很多关节提供了初始化函数,消除了大部分工作。然而,这些初始化函数通常只应用于原型,在产品代码中应该直接地定义几何数据。这能使关节行为更加稳固。

其余的关节定义数据依赖于关节的类型。

# 距离关节(distance-joint)

# 说明

使用距离关节连接的两个物体上的选定的两个点之间的距离是常量,它限制了两个物体之间的距离,使它始终保持一个常量,就像自行车的两个轮子。

# b2DistanceJointDef

距离关节是最简单的关节之一,它描述了两个物体上的两个点之间的距离应该是常量。当你指定一个距离关节时,两个物体必须已在应有的位置上。 随后,你指定两个世界坐标中的锚点 。第一个锚点连接到物体 1,第二个锚点连接到物体 2。这些点隐含了距离约束的长度。

首先创建两个物体,然后放到世界里,然后使用基类 b2DistanceJointDef 创建一个距离关节,连接它们。

每个距离关节都有两个锚点,分别赋予两个物体上某一点的坐标,这样子就使用一个距离关节将两个物体的选定点连起来。

var Shape1 = new b2BoxDef(); //创建一个形状Shape1
Shape1.extents.Set(10, 10);
Shape1.density = 1;
Shape1.restitution = 0.3;
Shape1.friction = 1;

var BodyDef1 = new b2BodyDef(); //用Shape1创建一个物体BodyDef1
BodyDef1.position.Set(300, 490);
BodyDef1.AddShape(Shape1);
Body1 = world.CreateBody(BodyDef1); //将BodyDef1放到世界里

var Shape2 = new b2BoxDef();
Shape2.extents.Set(20, 20);
Shape2.density = 1;
Shape2.restitution = 0.3;
Shape2.friction = 1;

var BodyDef2 = new b2BodyDef();
BodyDef2.position.Set(400, 480);
BodyDef2.AddShape(Shape2);
Body2 = world.CreateBody(BodyDef2);

var jointDefDistance = new b2DistanceJointDef(); //创建一个距离关节jointDefDistance
jointDefDistance.body1 = Body1; //该关节一端连在Body1上
jointDefDistance.body2 = Body2; //该关节另一端连在Body2上
jointDefDistance.anchorPoint1 = Body1.GetCenterPosition(); //关节和Body1的连接锚点是Body1的中心位置
jointDefDistance.anchorPoint2 = Body2.GetCenterPosition(); //关节和Body2的连接锚点是Body2的中心位置
var jointDistance = world.CreateJoint(jointDefDistance); //将距离关节jointDefDistance放入到世界中

# 旋转关节(revolute-joint)

# 说明

一个旋转关节会强制两个物体共享一个锚点,即铰接点。旋转关节只有一个自由度:两个物体的相对旋转。

旋转关节即相当于将两个物体用钉子钉在一起,两个物体都可以绕这颗钉子旋转。当然,如果其中一个物体为地面的话,就相当于将物体钉在地面上,物体都可以绕这颗钉子旋转。

# b2RevoluteJointDef

首先创建两个物体,然后将它们放在世界里,使用基类 b2RevoluteJointDef 创建一个旋转关节,设定铰接点,及旋转关节连接的是哪两个物体之后即可将其放入到世界里。

var jointDefRevolute = new b2RevoluteJointDef(); //创建一个旋转关节jointDefRevolute
jointDefRevolute.anchorPoint.Set(450, 450); //设定铰接点坐标
jointDefRevolute.body1 = Body1; //设定旋转关节一端连接Body1
jointDefRevolute.body2 = Body2; //设定旋转关节另一端连接Body2
var jointRevolute = world.CreateJoint(jointDefRevolute); //将旋转关节放入世界中
jointRevolute.SetMotorSpeed(100); //设置旋转关节马达的速度

# 移动关节(prismatic-joint)

# 说明

移动关节允许两个物体沿指定轴相对移动,它会阻止相对旋转,简而言之,就是关节对物体的影响只体现在轴向方向。因此,移动关节只有一个自由度。

移动关节类似旋转关节,只是将旋转角度换成了平移。关节中的两个刚体的相对运动只能发生在其轴向上。

# b2PrismaticJointDef

首先创建两个物体,将其放入世界里,然后使用基类 b2PrismaticJointDef 创建一个移动关节,设置其各个参数,再将其放入到世界里即可。

var jointDefPrismatic = new b2PrismaticJointDef(); //创建一个移动关节jointDefPrismatic
jointDefPrismatic.anchorPoint.Set(700, 565); //一般选择两个锚点的中心点
jointDefPrismatic.axis.Set(1, 0); //两物体只沿轴向方向有相对运动
jointDefPrismatic.body1 = Body1; //移动关节的一端连接到Body1上
jointDefPrismatic.body2 = Body2; //移动关节的另一端连接到Body2上
var jointPrismatic = world.CreateJoint(jointDefPrismatic); //将设置好参数的移动关节放到世界里

# 滑轮关节(pulley-joint)

# 说明

滑轮关节用于模拟定滑轮或动滑轮,即由滑轮关节连接的两个物体就像由绳子和滑轮连在一起一样。

在此,简单介绍动滑轮的特点,使用动滑轮能省一半力,但是费距离。 这是因为使用动滑轮时,物体由两段绳子吊着,每段绳子只承担钩码重的一半。使用动滑轮虽然省了力,但是动力移动的距离是钩码升高的距离的 2 倍,即费了距离。

一般可以简单地套用公式来计算 F 和 G 的关系: F=(G+G动滑轮)/n 对于滑轮组,n 代表接在动滑轮上的绳子的段数,而比例系数 ratio 即是 n。

# b2PulleyJointDef

创建好物体之后,用基类 b2PulleyJointDef 创建一个滑轮关节,然后分别设置其连接的是哪两个物体及其锚点,连接绳子顶点,两物体绳子最大长度及比例系数等参数即可。

var jointDefPulley = new b2PulleyJointDef(); //创建一个滑轮关节jointDefPulley
jointDefPulley.body1 = Body1; //滑轮关节的一端连接在Body1上
jointDefPulley.body2 = Body2; //滑轮关节的另一端连接在Body2上
jointDefPulley.anchorPoint1 = Body1.GetCenterPosition(); //滑轮关节与Body1的连接点是Body1的中心位置
jointDefPulley.anchorPoint2 = Body2.GetCenterPosition(); //滑轮关节与Body2的连接点是Body2的中心位置
var groundPoint1 = new b2Vec2(850, 345);
var groundPoint2 = new b2Vec2(950, 365);
jointDefPulley.groundPoint1 = groundPoint1;
jointDefPulley.groundPoint2 = groundPoint2; //用b2Vec2创建两个矢量,然后赋值给groundPoint,设定两段绳子的顶点
jointDefPulley.maxLength1 = 300;
jointDefPulley.maxLength2 = 100; //设定滑轮两侧的绳子的最大长度
//这两个maxLength至少有一个要大于|groundPoint-anchorPoint|   jointDefPulley.ratio=1;
//设定滑轮关节的比例系数,body1上下移动S,body2上下移动S/ratio,当ratio不等于1时,即模拟有动滑轮的情况

var jointPulley = world.CreateJoint(jointDefPulley); //将滑轮关节放到世界内

# 齿轮关节(gear-joint)

# 说明

齿轮关节需要两个被旋转关节或移动关节接地(ground)的物体,可以任意组合这些关节类型。

# b2PulleyJointDef

另外,创建旋转或移动关节时,Box2D 需要地(ground)作为 body1。

var Shape1 = new b2BoxDef(); //也可以是圆形或者多边形刚体
Shape1.extents.Set(10, 10);
Shape1.density = 1;
Shape1.restitution = 0.3;
Shape1.friction = 1;

var BodyDef1 = new b2BodyDef();
BodyDef1.position.Set(950, 450);
BodyDef1.AddShape(Shape1);
Body1 = world.CreateBody(BodyDef1);

var jointDefRevolute = new b2RevoluteJointDef(); //创建一个旋转关节
jointDefRevolute.anchorPoint.Set(950, 450);
jointDefRevolute.body1 = world.GetGroundBody(); //用作齿轮关节的旋转关节body1须为GroundBody
jointDefRevolute.body2 = Body1; //将旋转关节另外一个物体设为Body1
var jointRevolute = world.CreateJoint(jointDefRevolute); //将旋转关节放入世界中

var Shape2 = new b2BoxDef();
Shape2.extents.Set(100, 10);
Shape2.density = 1;
Shape2.restitution = 0.3;
Shape2.friction = 1;

var BodyDef2 = new b2BodyDef();
BodyDef2.position.Set(950, 530);
BodyDef2.AddShape(Shape2);
Body2 = world.CreateBody(BodyDef2);

var jointDefPrismatic = new b2PrismaticJointDef(); //创建一个移动关节
jointDefPrismatic.anchorPoint.Set(950, 565);
jointDefPrismatic.axis.Set(1, 0); //在齿轮关节中,这个轴只要设置成平行于屏幕就行,也就是说随着齿轮旋转,移动关节可以上下、左右来回运动,(斜向运动会出现bug)
jointDefPrismatic.body1 = world.GetGroundBody(); //用作移动关节的移动关节body1须为GroundBody
jointDefPrismatic.body2 = Body2; //移动关节的另外一个物体设置为Body2
var jointPrismatic = world.CreateJoint(jointDefPrismatic); //将移动关节放入到世界中

var jointDefGear = new b2GearJointDef(); //使用基类b2GearJointDef创建一个齿轮关节
jointDefGear.body1 = Body1;
jointDefGear.body2 = Body2; //设置齿轮关节连接的两个物体分别是Body1和Body2
jointDefGear.joint1 = jointRevolute;
jointDefGear.joint2 = jointPrismatic;
var jointGear = world.CreateJoint(jointDefGear); //将齿轮关节放入到世界中
jointGear.m_ratio = 1; //设定比例系数,ratio=转动圈数/移动距离
部分文章中使用了一些网站的截图,如果涉及侵权,请告诉我删一下谢谢~
温馨提示喵