box2dbox2dweb

When creating a joint during runtime, object teleports


I have two objects and when the distance between them is less than 10, I create a joint:

var joint_def = new box2d.b2RevoluteJointDef();
joint_def.bodyA = body1;
joint_def.bodyB = body2;
joint_def.localAnchorA = new box2d.b2Vec2(0, 0);
joint_def.localAnchorB = new box2d.b2Vec2(0, 0);
world.CreateJoint(joint_def);

The problem is, however, that one object teleports/jumps on top of the other. The intended behavior would be that one object slowly moves on top of the other.

Any idea? Thanks.


Solution

  • I believe you have two problems:

    Problem #1: The localAnchorA and localAnchorB are the point that you want the joint to be at. This would be the point in world space mapped into the local coordinate system of the respective bodies. You can do this manually, or you can do this with a function on the joint_def (at least that is the way it works in c++):

    Automatically:

    b2RevoluteJointDef jointDef;
    b2Vec2 anchor = _body->GetWorldCenter();
    jointDef.Initialize(_body, otherBody, anchor);
    jointDef.collideConnected = true;
    _world->CreateJoint(&jointDef);
    

    Manually:

       b2RevoluteJointDef jointDef;
       b2Vec2 anchor = _body->GetWorldCenter();
       jointDef.bodyA = _body;
       jointDef.bodyB = otherBody;
       jointDef.localAnchorA = _body->GetLocalPoint(anchor);
       jointDef.localAnchorB = otherBody->GetLocalPoint(anchor);
       jointDef.referenceAngle = otherBody->GetAngle() - _body->GetAngle();
       _world->CreateJoint(&jointDef);
    

    You are initializing the anchor points (both of them) with b2Vec2(0,0). I'm going to use this code base to demonstrate what the difference looks like:

    When you have both anchor points defined in the local space of each body:

    enter image description here

    Note that the "T" is rotating but the other body is not moving. But the joint is keeping them at a rotated distance from each other.

    If you have both the local anchor points set to (0,0):

    enter image description here

    In general, if you have the Initialize(...) method, use it to create the joint.

    Problem #2: If you start out with the bodies 10m apart and that is where you create your revolute joint, that is where they will stay. If you want them to start moving towards each other...I think the easiest way to do this (and I have done it...see here) is to attach a rope joint between the two and then, every "update" of the physics loop, do something like this (knowing that the rope joint is the first and only joint connected to the body):

      b2JointEdge* jointEdge = GetBody()->GetJointList();
      b2RopeJoint* rope = (b2RopeJoint*)jointEdge->joint;
      rope->SetMaxLength(rope->GetMaxLength()-_ropeClimbDistPerUpdate);
    

    When the rope length gets less than some tolerance, connect your revolute joint. It works pretty good to make spiders swing from asteroids...

    NOTE You can also use a b2DistanceJoint instead of a b2RopeJoint. The rope joint constrains the maximum distance while the distance joint constrains the fixed distance. For this situation, it should work out about the same. The rope joint may not be present in other box2d ports.

    Was this what you needed?