跳至正文

(转载)BOX2D V2.3.0 用户手册中文版(第7章)-夹具

Chapter 7 夹具

7.1 关于

回想一下,形状不知道物体的存在,并可独立于物理模拟而被使用。因此Box2D提供b2Fixture类,用于将形状附加到物体上。一个物体可以有零个或多个fixture。拥有多个fixture的物体有时被叫做组合物体。
fixture具有下列属性:
• 关联的形状
• broad-phase代理
• 密度(density)、摩擦(friction)和恢复(restitution)
• 碰撞筛选标记(collision filtering flags)
• 指向父物体的指针
• 用户数据
• 传感器标记(sensor flag)
这些都会在接下来的小节中描述。

7.2 创建夹具

要创建fixture,先要创始化一个fixture定义,并将定义传到父物体中。

b2FixtureDef fixtureDef;
fixtureDef.shape = &myShape;
fixtureDef.density = 1.0f;
b2Fixture* myFixture = myBody->CreateFixture(&fixtureDef);

这会创建fixture,并将它附加到物体之上。你不需要保存fixture的指针,因为当它的父物体被摧毁时,fixture也会自动被摧毁。 你可以在单个物体上创建多个fixture。
你可以摧毁父物体上的fixture,来模拟一个可分裂开的物体。你也可以不理会fixture,让物体的析构函数来摧毁附加其上的fixture。

myBody->DestroyFixture(myFixture);

密度

fixture的密度用来计算父物体的质量属性。密度值可以为零或者是正数。你所有的fixture都应该使用相似的密度,这样做可以改善堆叠稳定性。
当设置密度的时候,物体的质量不会立即改变。你必须调用ResetMassData ,使之生效。

fixture->SetDensity(5.0f);
body->ResetMassData();

摩擦

摩擦可以使对象逼真地沿其它对象滑动。Box2D支持静摩擦和动摩擦,两者都使用相同的参数。摩擦在Box2D中会被精确地模拟,摩擦力的强度与正交力 (称之为库仑摩擦)成正比。摩擦参数通常会设置在0到1之间,但也可是任意的非负数,0意味着没有摩擦,1会产生强摩擦。当计算两个形状之间的摩擦力时,Box2D必须组合两个形状的摩擦参数。这是通过以下公式完成的:

float32 friction;
friction = sqrtf(fixtureA->friction * fixtureB->friction);

所以当其中一个fixture的摩擦参数为0时,接触的摩擦就为0。
你可以用b2Contact::SetFriction 重载默认的合成摩擦的方法。这通常是在b2ContactListener 的回调中执行的。

恢复

恢复可以使对象弹起。恢复的值通常设置在0到1之间。想象一个小球掉落到桌子上,值为0表示着小球不会弹起, 这称为非弹性碰撞。值为1表示小球的速度跟原来一样,只是方向相反,这称为完全弹性碰撞。恢复是通过下面的公式合成的:

float32 restitution;
restitution = b2Max(fixtureA->restitution, fixtureB->restitution);

因为恢复是以这样的方式合成,因此你可以指定一个有弹性的球,而不用指定一个有弹性的地板。
你可以用b2Contact:: SetRestitution 重载默认的合成恢复的方法。这通常是在b2ContactListener 的回调中执行的。
当一个形状多次碰撞时,恢复会被近似地模拟,这是因为Box2D使用了迭代求解器。当冲撞速度很小时,Box2D也会使用非弹性碰撞,这是为了防止抖动。参见b2Settings.h中的b2_velocityThreshold 。

筛选

碰撞筛选是为了防止某些fixture之间发生碰撞。比如,你创造了一个骑自行车的角色。你希望自行车与地形之间有碰撞,角色与地形有碰撞,但你不希望角色和自行车之间发生碰撞 (因为它们必须重叠)。Box2D通过种群和分组来支持这样的碰撞筛选。
Box2D支持16个种群。任意fixture你都可以指定它属于哪个种群。你还可以指定这个fixture可以和其它哪些种群发生碰撞。例如,你可以在一个多人游戏中指定玩家之间不会碰撞,怪物之间也不会碰撞,但是玩家和怪物会发生碰撞。这是通过掩码来完成的,例如:

playerFixtureDef.filter.categoryBits = 0x0002;
monsterFixtureDef.filter.categoryBits = 0x0004;
playerFixtureDef.filter.maskBits = 0x0004;
monsterFixtureDef.filter.maskBits = 0x0002;

下面是产生碰撞的规则:

uint16 catA = fixtureA.filter.categoryBits;
uint16 maskA = fixtureA.filter.maskBits;
uint16 catB = fixtureB.filter.categoryBits;
uint16 maskB = fixtureB.filter.maskBits;

if ((catA & maskB) != 0 && (catB & maskA) != 0)
{
  // fixtures can collide
}

碰撞分组让你指定一个整数的组索引。你可以让同一个组的所有fixture总是相互碰撞(正索引)或永远不碰撞(负索引)。组索引通常用于一些以某种方式关联的事物,就像自行车的那些部件。在下面的例子中,fixture1 和 fixture2 总是碰撞,而 fixture3 和 fixture4 永远不会碰撞。

fixture1Def.filter.groupIndex = 2;
fixture2Def.filter.groupIndex = 2;
fixture3Def.filter.groupIndex = -8;
fixture4Def.filter.groupIndex = -8;

如果组索引不同,碰撞筛选就会按照种群和掩码来进行。换句话说,分组筛选与种群筛选相比,具有更高的优选级。
注意在 Box2D 中还有其它的碰撞筛选,这里是一个列表:
• static上的fixture只会与dynamic物体上的fixture发生碰撞。
• kinematic物体 只会和dynamic物体碰撞。
• 同一个物体上的fixture永远不会相互碰撞。
• 如果两个物体用关节连接起来,物体上面的fixture可以选择启用或禁止它们之间相互碰撞。
有时你可能希望在形状创建之后去改变其碰撞筛选。 你可以使用b2Fixture::GetFilterData 和b2Fixture::SetFilterData来访问和设置已存在的fixture的b2FilterData结构。注意就算修改了筛选数据,到下一个时间步 为止,现在的接触并不会被增加或删除(参见world类)。

7.3 传感器

有时候游戏逻辑需要判断两个fixture是否相交,而不想有碰撞反应。这可以通过传感器(sensor)来完成。传感器也是个fixture,但它只会侦测碰撞,而不产生其它反应。
你可以将任意fixture标记为传感器。传感器可以是static、kinematic或dynamic的。记住,每个物体上可以有多个fixture,传感器和实体fixture是可以混合存在的。而且,只有至少一个物体是dynamic的,传感器才会产生接触事件,而kinematic 与kinematic 、kinematic 与static ,或者static 与static 之间都不会产生接触事件。
传感器不会生成接触点。这里有两种方法得到传感器的状态:
1. b2Contact::IsTouching
2. b2ContactListener::BeginContact 和 EndContact

标签:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注