There seems to be an issue with the gear joint in 2.2.0 that is not present in 2.1.3.
Having a gear joint set up with two revolute joints and a *negative* gear ratio can result in the simulation breaking when other bodies interact with the 'bodyA' of the gear joint.
Having a *positive* ratio in the gear joint still works as expected in all the cases I've tried.
I'm also reasonably certain the issue only happens when 'bodyA' of the gear joint is interacted with, 'bodyB' seems to work as expected.
Here's a simple testbed example, just done as a replacement for the 'Gears' test. If you watch it for a few seconds the simulation will explode.
Note that the weld joint in this example is included just to make reproducing the issue a lot simpler. You could also remove the weld joint and simply use the mouse joint to 'stroke' the leftmost box with the small box and see the same problem, but there is a definite knack to doing this :0)
Code:
class Gears : public Test
{
public:
Gears()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
// leftmost large box
b2PolygonShape box1;
box1.SetAsBox(5.f, 5.f);
b2BodyDef bd1;
bd1.type = b2_dynamicBody;
bd1.position.Set(-10.0f, 10.0f);
b2Body* body1 = m_world->CreateBody(&bd1);
body1->CreateFixture(&box1, 5.0f);
b2RevoluteJointDef jd1;
jd1.bodyA = ground;
jd1.bodyB = body1;
jd1.localAnchorA = ground->GetLocalPoint(bd1.position);
jd1.localAnchorB = body1->GetLocalPoint(bd1.position);
jd1.referenceAngle = body1->GetAngle() - ground->GetAngle();
m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd1);
// rightmost large box
b2PolygonShape box2;
box2.SetAsBox(5.f, 5.f);
b2BodyDef bd2;
bd2.type = b2_dynamicBody;
bd2.position.Set(5.0f, 10.0f);
b2Body* body2 = m_world->CreateBody(&bd2);
body2->CreateFixture(&box2, 5.0f);
b2RevoluteJointDef jd2;
jd2.Initialize(ground, body2, bd2.position);
m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd2);
#if 1
// small box
// create & weld to the leftmost box to see the bug
// if the gear ratio is also set to -1 below
b2PolygonShape box;
box.SetAsBox(1.f, 1.f);
b2BodyDef boxd2;
boxd2.type = b2_dynamicBody;
boxd2.position.Set(-8.0f, 16.0f);
b2Body* boxbody = m_world->CreateBody(&boxd2);
boxbody->CreateFixture(&box, 5.0f);
b2WeldJointDef jd3;
jd3.Initialize(boxbody, body1, body1->GetPosition());
m_joint3 = (b2WeldJoint*)m_world->CreateJoint(&jd3);
#else
// small box
// create & weld to the rightmost box to see the
// expected behaviour regardless of gear ratio
b2PolygonShape box;
box.SetAsBox(1.f, 1.f);
b2BodyDef boxd2;
boxd2.type = b2_dynamicBody;
boxd2.position.Set(7.0f, 16.0f);
b2Body* boxbody = m_world->CreateBody(&boxd2);
boxbody->CreateFixture(&box, 5.0f);
b2WeldJointDef jd3;
jd3.Initialize(boxbody, body2, body2->GetPosition());
m_joint3 = (b2WeldJoint*)m_world->CreateJoint(&jd3);
#endif
// gear joint
b2GearJointDef jd4;
jd4.bodyA = body1;
jd4.bodyB = body2;
jd4.joint1 = m_joint1;
jd4.joint2 = m_joint2;
#if 1
// set the ratio to -1 to see the bug if the small box is also
// welded to the leftmost large box, above
jd4.ratio = -1;
#else
// set the ratio to 1 to see the expected behaviour regardless
// of which box is welded above
jd4.ratio = 1;
#endif
m_joint4 = (b2GearJoint*)m_world->CreateJoint(&jd4);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 0:
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
}
static Test* Create()
{
return new Gears;
}
b2RevoluteJoint* m_joint1;
b2RevoluteJoint* m_joint2;
b2WeldJoint* m_joint3;
b2GearJoint* m_joint4;
};