简体   繁体   中英

libGDX Box2D: How to destroy body after collision?

Thanks for your time.

I am creating a Pong clone using Box2D via libGDX. When trying to delete the Ball body as a result of the Ball body contacting with one of the two Goal Sensor Bodies (image below), I am having a sticking point that results in a Null Pointer Exception.

I want to add the contacting Ball body to a list so that I can later iterate through the list to delete the Ball body (and multiple Ball bodies in the future).

在此处输入图像描述

The stack trace:

Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.physics.box2d.World.destroyBody(World.java:311)
at com.ckq3r.Ponger.screens.GameScreen.update(GameScreen.java:484)
at com.ckq3r.Ponger.screens.GameScreen.render(GameScreen.java:114)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.ckq3r.Ponger.PongerGame.render(PongerGame.java:236)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:204)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:112)

Line 484 in my GameScreen class is the line world.destroyBody(circleBody); that resides within the if(scoredGoal1 == true){stuff} conditional statement of the the public void render(float delta){stuff} method shown below.

public class GameScreen implements Screen, InputProcessor{

/*----methods and variables omitted for readability------*/

private boolean scoredGoal1 = false, scoredGoal2 = false;
ArrayList<Body> ballDeletionList = new ArrayList<Body>();

/*==============Screen implementation methods============*/
    @Override
    public void show(){
        /*ball*/
        BodyDef circleDef = new BodyDef();      
        Body circleBody = world.createBody(circleDef);
        circleBody.setUserData(1);              
        CircleShape circleShape = new CircleShape();                
        FixtureDef circleFixture = new FixtureDef();
        circleFixture.shape = circleShape;              
        circleBody.createFixture(circleFixture);        
        circleShape.dispose();
    }

    @Override
    public void render(float delta) {           
        world.step(Gdx.app.getGraphics().getDeltaTime(), 8, 3);
        Gdx.gl.glClearColor(0, 0, 0, 1); 
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        camera.update();
        debugRenderer.render(world, camera.combined);

        /*-------ball deletion experiment-------*/          
        if(scoredGoal1 == true){

            //iterate through ballDeletionList somehow?

            world.destroyBody(circleBody);                            
            circleBody.setUserData(null);
            circleBody = null;                              
            scoredGoal1 = false;
            //clear ballDeletionList

        }else if(scoredGoal2 == true){

            //iterate through ballDeletionList somehow?

            world.destroyBody(circleBody);
            circleBody.setUserData(null);
            circleBody = null;              
            scoredGoal2 = false;
            //clear ballDeletionList
        }
        /*-----end ball deletion experiment------*/
}   

/*===========Box2D contact listener=============*/
    private void createContactListener() {
        world.setContactListener(new ContactListener() {

        @Override
        public void beginContact(Contact contact) {
            Fixture fixtureA = contact.getFixtureA();
            Fixture fixtureB = contact.getFixtureB();
            Gdx.app.log("beginContact", "between " + fixtureA.toString() + " and " + fixtureB.toString());

            if(fixtureA.getBody().getUserData().equals(1) && fixtureB.getBody().getUserData().equals(2) || fixtureA.getBody().getUserData().equals(2) && fixtureB.getBody().getUserData().equals(1)){
                Gdx.app.log("HIT", "goal1 contact");

                /*ball deletion experiment*/
                ballDeletionList.add(circleBody);
                Gdx.app.log("Ball", "circleBody added to deletion list");
                scoredGoal1 = true;
                /*ball deletion experiment*/
            }         

            if(fixtureA.getBody().getUserData().equals(1) && fixtureB.getBody().getUserData().equals(3) || fixtureA.getBody().getUserData().equals(3) && fixtureB.getBody().getUserData().equals(1)){
                Gdx.app.log("HIT", "goal2 contact");

                /*ball deletion experiment*/
                ballDeletionList.add(circleBody);
                Gdx.app.log("Ball", "circleBody added to deletion list");
                scoredGoal2 = true;
                /*ball deletion experiment*/
            }
        }                

        });

My logic is as follows on contact between a Ball body and a Goal Sensor body:

  1. From within the ContactListener's beginContact() method, the Ball body contacting with the EdgeShape Sensor body will be added to the ArrayList<Body> ballDeletionList = new ArrayList<Body>(); and the scoredGoal1 = true; boolean flag will be set to true.
  2. In the render(); check for scoredGoal1 = true or scoredGoal2 = true then delete the applicable Body/Bodies after the world.step() method.

I have searched other code examples and tutorials throughout the web only to find answers that are ambiguous because either the code was case specialized or I only understand Java at the moment.

It would be great if a Java/libGDX code example solution could be posted.

You can't delete bodies in your contactlistener because that is inside your world step, and world is locked. I did exactly the same you are trying to do, in your render method just:

if(ballDeletionList.size>0) ballDeletionList.clear();

Also, using libgdx it is recommended to use Array http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Array.html instead of ArrayList, it generates less garbage and makes some more optimizations.

Please, do you have any simple example on how to destroy a body?

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