7
\$\begingroup\$

I get this error when attempting to remove a body from the world:

java: /var/lib/hudson/jobs/libgdx/workspace/trunk/gdx/jni/Box2D/Dynamics/b2World.cpp:134: void b2World::DestroyBody(b2Body*): Assertion 'IsLocked() == false' failed.

What am I doing wrong?

\$\endgroup\$
  • 3
    \$\begingroup\$ Did you actually read that error? \$\endgroup\$ – o0'. Apr 10 '12 at 7:20
21
\$\begingroup\$

From my little experience with box2d in libgdx, it can sometimes be difficult to isolate and resolve issues with exceptions which was only worsened by the latest port. Pre 2.2.1, I could easily remove bodies from the world without synchronization issues like you are experiencing but after migrating to the libgdx build that supported 2.2.1, I started seeing the same issues. The workaround for me, which was suggested by several people was that you cannot remove bodies from the world while the world is possibly being simulated.

Is there a possibility that you are attempting to remove a body from the world when the world is being stepped? Basically, if you try to do this, box2d doesn't like it so what you have to do is remove bodies outside of the world.step. What I did was added a utility class for the body's .userData with a bool isFlaggedForDelete which would get checked outside the world.step method.

public void sweepDeadBodies() {
   for (Iterator<Body> iter = CURRENT_WORLD.getBodies(); iter.hasNext();) {
     Body body = iter.next();
     if(body!=null) {
          YourCustomUserData data = (YourCustomUserData) body.getUserData();
          if(data.isFlaggedForDelete) {
          CURRENT_WORLD.destroyBody(body);
            body.setUserData(null);
            body = null;
          }
     }
}

If you run something like this right after your world.step, it should work. In your code where you are trying to destroy the body, just set it's .isFlaggedForDelete to true and it will get removed before the next world.step.

\$\endgroup\$
  • 2
    \$\begingroup\$ For worlds containing lots of bodies, the sweepDeadBodies method proposed here wastes lots of cycles iterating through bodies that aren't going to be deleted. In such cases, consider pushing pointers to the to-be-destroyed bodies onto a deadBodies list in an outer scope, then iterating through that after the step, clearing it once done. \$\endgroup\$ – Anko Oct 12 '15 at 18:27
5
\$\begingroup\$

So we have your error:

/var/lib/hudson/jobs/libgdx/workspace/trunk/gdx/jni/Box2D/Dynamics/b2World.cpp:134: void b2World::DestroyBody(b2Body*): Assertion 'IsLocked() == false' failed.

Let's break it down:

Most of the first part of this error is helpful directions to tell you where the error is happening.

/var/lib/hudson/jobs/libgdx/workspace/trunk/gdx/jni/Box2D/Dynamics/b2World.cpp

It appears the error is being generated in a source file called b2World.cpp inside the directory structure shown. And it's happening:

:134:

On line 134.

Then it looks like,

void b2World::DestroyBody(b2Body*):

the function b2World:DestroyBody() which returns void and accepts a pointer to a b2Body is reporting the error.

That has finished the "where" part of the error, now it's telling us the "what". Looks like it's trying to assert that isLocked() is equal to false

Assertion `IsLocked() == false' failed.

But it's failing.

Now I've never used Box2D, but I'm guessing that means the body you're trying to destroy is locked. You'll need to figure out why the body is locked, and how to unlock it.

\$\endgroup\$
4
\$\begingroup\$

Libgdx implementation is just bridge to native version so all the same rules apply.

Never try to remove a body/fixture/joint when the simulation is running.

Never try to remove a body/fixture/joint more than once.

Never leave pointers (aka references) to fixtures or joints when you delete the body.

To be extra cautious - maybe even little paranoid - I use this method to remove my bodies:

/**
 * Safe way to remove body from the world. Remember that you cannot have any
 * references to this body after calling this
 *
 * @param body
 *            that will be removed from the physic world
 */

public static void removeBodySafely(Body body) {
    //to prevent some obscure c assertion that happened randomly once in a blue moon
    final ArrayList<JointEdge> list = body.getJointList();
    while (list.size() > 0) {
        world.destroyJoint(list.get(0).joint);
    }
    // actual remove
    world.destroyBody(body);
}
\$\endgroup\$
2
\$\begingroup\$

This is the best way to do it, i read it in the Box2D manual. You have to call this just after CURRENT_WORLD.step(..,...,...);

Iterator<Body> i = CURRENT_WORLD.getBodies();
Body node=i.next();
while (i.hasNext()) {
    Body oBj=node;
    node=i.next();
    YourCustomUserData data = (YourCustomUserData) oBj.getUserData();
    if(data!=null &&  data.isFlaggedForDelete){
        CURRENT_WORLD.destroyBody(oBj);             
    }
}
\$\endgroup\$
  • \$\begingroup\$ yes.... works great \$\endgroup\$ – Vishal Kumar Apr 30 '14 at 20:54
0
\$\begingroup\$

The error says it all, you need to check if the world is locked in the moment that you want to remove the body

if(!world.isLocked())
     world.destroyBody(body)

that worked for me :)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.