简体   繁体   中英

Delete body box2d

Could anyone tell me why this is returning the error

'AL lib: (EE) alc_cleanup: 1 device not closed'

//mouseJoint collision callback

private QueryCallback queryCallback = new QueryCallback() {

    @Override
    public boolean reportFixture(Fixture fixture) {


        if(fixture.getBody() == chest){

            //add to remove list

            bodiesToRemove.add(chest);

        }

        if (fixture.testPoint(tmp.x, tmp.y)){


            reportFixture = fixture.getBody();
        }


        if (!fixture.testPoint(tmp.x, tmp.y))
            return false;

        //assigning bodyB to fixture 
        jointDef.bodyB = fixture.getBody();
        jointDef.target.set(fixture.getBody().getWorldCenter());

        //jointDef.target.set(tmp.x, tmp.y);// initial target point coincide with body anchor

        joint = (MouseJoint) world.createJoint(jointDef);// creating the join the physics world
        return false;
    }

};

//main rendering loop

public void render(float delta) {
    // TODO Auto-generated method stub
       //code clears the screen with the given RGB colour (black)
    Gdx.gl.glClearColor( 0f, 0f, 0f, 1f );
    Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );


     stage.setCamera(camera);               
     stage.act(Gdx.graphics.getDeltaTime());




    camera.position.x= chest.getPosition().x;


    camera.update();

     stage.draw();



    world.step(1 / 60f, 8, 3);
    renderer.render(world, camera.combined);


/////////////////////////////////////////////////////////////////   

// this is the code that is causing the error when I try to delete a body

    if(bodiesToRemove != null){

    for(int i = 0; i <bodiesToRemove.size; i++){

        Body b = bodiesToRemove.get(i);

        if(b != null){
           world.destroyBody(b);
           b.setUserData(null);
           b = null;
        }
        bodiesToRemove.clear();
    }
    }

    ////////////////////////////////////////////////////////////
}

//////////////////////////////////////////////////////////////////////////// I've changed this and it work's(pasted below), if anyone would like to explain the right way to do this or if this is the correct way that would be helpful. I just added a boolean to prevent it from destroying the joint

// ////////////////// TOUCH EVENT ///////////////////////////////
//Called when a finger was lifted or a mouse button was released.
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
    //If no mouseJoint do nothing

    System.out.println("touch" + (screenY*0.01f));
    System.out.println("touch" + (screenX*0.01f));



    if (joint == null)
        return false;


    //When user is not touching Screen destroy the
    //mouseJoint/set to null
    if(ran == false){

    world.destroyJoint(joint);
    joint = null;}


    ran = false;
    return true;
}



////////////////////////////////

/////////////////////////////////

    if(!world.isLocked() && world.getBodyCount() > 0 ){

        for(int i = 0; i <bodiesToRemove.size; i++){

            Body b = bodiesToRemove.get(i);

            if(b == null){
                bodiesToRemove.removeIndex(i);
                continue;
            }
            world.destroyBody(b);
            ran = true;
            bodiesToRemove.removeIndex(i);

        }

        }else{

            bodiesToRemove.clear();
        }

    ////////////////////////////////////////////////////////////

Box2D throws some odd errors, this is not one of them.

I assume you are using LibGDX, basically what is happening is a crash due to Box2D (I also assume it pops up saying "java or whatever has stopped responding"), this error you are seeing is thrown when the app exits while OpenAL is closing streams and cleaning up resources. Don't worry about that too much.

Ensure you are checking of the world is locked before destroying bodies, it usually throws an error and prints a clear message telling you this, depending on the way you are removing bodies.

if(!world.isLocked())
    // do clean up code here

You don't need to clean up the variable inside local scope, or clear the userdata inside the body as the body as it will no longer exist in reference (unless you have it stored somewhere else).

So the proper code would be something like this:

if(!world.isLocked()){
    for(int i = bodiesToRemove.size - 1; i--){
        Body b = bodiesToRemove.get(i);
        if(b == null){
            bodiesToRemove.removeAt(i);
            continue;
        }
        world.destroyBody(b);
        bodiesToRemove.removeAt(i);
    }
}

You are also clearing a list during iteration, not a good idea.

EDIT

The only other thing I can think of that is causing this problem is trying to delete a body that is not actually in the worlds body list.

Try the following:

// Ensure world is not locked AND that there is even bodies in the world
if(!world.isLocked() && world.getBodyCount() > 0){
    for(int i = bodiesToRemove.size - 1; i--){
        Body b = bodiesToRemove.get(i);
        if(b == null){
            bodiesToRemove.removeAt(i);
            continue;
        }
        world.destroyBody(b);
        bodiesToRemove.removeAt(i);
    }
}else{
    // There is no bodies in the world, so the bodies in our list are just
    // random memory hogs, leave them for the GC by clearing the list
    bodiesToRemove.clear();
}

EDIT

As stated by the OP, the problem lies with this block of code:

private QueryCallback queryCallback = new QueryCallback() {

@Override
public boolean reportFixture(Fixture fixture) {
    if(fixture.getBody() == chest){
        //add to remove list
        bodiesToRemove.add(chest);
    }
    if (fixture.testPoint(tmp.x, tmp.y)){
        reportFixture = fixture.getBody();
    }
    if (!fixture.testPoint(tmp.x, tmp.y))
        return false;
    //assigning bodyB to fixture 
    jointDef.bodyB = fixture.getBody();
    jointDef.target.set(fixture.getBody().getWorldCenter());
    //jointDef.target.set(tmp.x, tmp.y);
    joint = (MouseJoint) world.createJoint(jointDef);
    return false;
}

};

More specifically, this line:

    joint = (MouseJoint) world.createJoint(jointDef);

The query callback is triggered during a world step. In Box2D, you can not create or destroy bodies, fixtures, and joints during the world step.

You have to create it outside this method, the simplest way to do it is via a flag. Set a flag to true and store the instance of the fixture somewhere and handle it outside in the game loop using said flag and fixture.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM