书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录
5.11 Box2D关节
1)3种类型
Box2D的关节能将两个物体连接在一起,常用于一些高级物理模拟,比如钟摆的摆动、弹簧连接、粘性物体和轮子滚动等。Box2D的关节分成多种类型,在本章,我们会学习以下3种类型的关节:
- 距离关节、
- 旋转关节
- 和鼠标关节。
2)距离关节
让我们从距离关节开始,距离关节用固定的长度将两个物体连接在一起。关节通过锚点(相对于物体中心点的坐标)连接到物体上。对任何Box2D关节,我们都需要按照一定的步骤将它们和物体相连,方法和前面创建物体和形状一样。
- 步骤1:确保程序中有两个物体。
- 步骤2:定义关节。
- 步骤3:配置关节的属性。(连接哪些物体?锚点在哪里?它的静止长度是多少?它是弹性的还是刚性的?)
- 步骤4:创建关节。
图5-10
- 假设有两个粒子对象p1和p2,它们分别有一个引用指向Box2D物体对象
Particle p1 = new Particle();
Particle p2 = new Particle();
- 下面转向步骤2,让我们来定义关节。
DistanceJointDef djd = new DistanceJointDef();
- 下面我们要做的是配置关节的属性。
首先,我们需要指定它连接的物体:
djd.bodyA = p1.body;
djd.bodyB = p2.body;
- 然后,设定一个静止长度。记住,如果静止长度是用像素表示的,我们应该先将它转化为Box2D长度。
djd.length = box2d.scalarPixelsToWorld(10);
- 距离关节还有两个可选设置,这两个设置能让关节具有弹性,就像是弹簧的连接。它们分别是:frequencyHz和dampingRatio。
djd.frequencyHz = ___; 以赫兹为单位,就像简谐振荡的频率,你可以试着填入1~5的数字
djd.dampingRatio = ___; 弹性阻尼,介于0~1
- 最后,创建关节。
DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd);
Box2D并不会记录关节类型,因此我们需要将它强制转成DistanceJoint类型。
我们可以在Sketch的任意位置创建Box2D关节。下面的例子展示了如何用类描述物体之间的关节连接。
3)示例代码
示例代码5-6 距离关节
class Pair {
Particle p1; 两个具有Box2D物体引用的对象
Particle p2;
float len;
// Chain constructor
Pair(float x, float y) {
len = 32; 任意静止长度
p1 = new Particle(x,y); 如果所有物体都在相同的位置,就会出现问题
p2 = new Particle(x+random(-1,1),y+random(-1,1));
DistanceJointDef djd = new DistanceJointDef(); 创建关节!
// Connection between previous particle and this one
djd.bodyA = p1.body;
djd.bodyB = p2.body;
// Equilibrium length
djd.length = box2d.scalarPixelsToWorld(len);
// These properties affect how springy the joint is
djd.frequencyHz = 3; // Try a value less than 5 (0 for no elasticity)
djd.dampingRatio = 0.1; // Ranges between 0 and 1 (1 for no springiness)
// Make the joint. Note we aren't storing a reference to the joint ourselves anywhere!
// We might need to someday, but for now it's ok
DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd);
创建关节,注意我们并没有存放关节引用!后面我们可能需要使用它
}
void display() {
Vec2 pos1 = box2d.getBodyPixelCoord(p1.body);
Vec2 pos2 = box2d.getBodyPixelCoord(p2.body);
stroke(0);
strokeWeight(2);
line(pos1.x,pos1.y,pos2.x,pos2.y);
p1.display();
p2.display();
}
}