How to handle Null Pointer Exception in libGDX'

2019-08-18 03:12发布

问题:

What's up everyone,

I am heuristically producing a Pong clone in Box2D via libGDX. The Null Pointer Exception is originating in the ContactListener's beginContact() method in which I am trying to implement score logic.

The Box2D world uses two separate EdgeShapes as sensors for incrementing a score variable upon collision with the Ball (view attached image). The collision logic between the Ball and the two EdgeShapes works, but collision between the Ball and anything else in the Box2D world crashes the program.

The stack trace:

Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.ckq3r.Pong.screens.GameScreen$2.beginContact(GameScreen.java:491)
at com.badlogic.gdx.physics.box2d.World.beginContact(World.java:876)
at com.badlogic.gdx.physics.box2d.World.jniStep(Native Method)
at com.badlogic.gdx.physics.box2d.World.step(World.java:602)
at com.ckq3r.Pong.screens.GameScreen.render(GameScreen.java:99)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.ckq3r.Pong.PongGame.render(PongGame.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)

The problematic code:

    /**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");
                score1++;
                score1String = score1 + "";
            }

            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");
                score2++;
                score2String = score2 + "";
            }
        }

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

        @Override
        public void preSolve(Contact contact, Manifold oldManifold) {
        }

        @Override
        public void postSolve(Contact contact, ContactImpulse impulse) {
        }

        });
} 

Notes:

  1. When I comment out the two conditional statements within the beginContact() method, the code runs. When uncommented, the error is reproduced.
  2. The Ball userData is circleBody.setUserData(1);
  3. The goal1 userData is goalBody.setUserData(2);
  4. The goal2 userData is goalBody.setUserData(3);

回答1:

Set the userdata for each body in the Box2D world so that you can use conditional logic within the ContactListener to assess whether or not the collision should be handled.

With the emphasis being on the line paddleBody.setUserData(4); below. You can pick any number to set to the userdata of the individual object, so long as the number is unique from the userdata of the other objects within your world.

For example:

    /**paddle1**/
    BodyDef paddleDef = new BodyDef();
    paddleDef.type = BodyType.DynamicBody;
    paddleDef.position.set(width * 0.2f, height / 2);
    paddleDef.fixedRotation = true;

    Body paddleBody = world.createBody(paddleDef);
    paddleBody.setUserData(4);

    PolygonShape paddleShape = new PolygonShape();
    paddleShape.setAsBox(3.0f, 15.0f); //half-width and half-height

    FixtureDef paddleFD = new FixtureDef();
    paddleFD.shape = paddleShape;
    paddleFD.density = 10.0f;
    paddleFD.friction = 0.0f;
    paddleFD.restitution = 0.1f;

    paddleBody.createFixture(paddleFD);

    paddleShape.dispose();

    paddleBody.setLinearVelocity(0.0f, 0.0f);
    /**end paddle1**/

    /**paddle2**/
    BodyDef paddleDef2 = new BodyDef();
    paddleDef2.type = BodyType.DynamicBody;
    paddleDef2.position.set(width * 0.8f, height / 2);
    paddleDef2.fixedRotation = true;        

    Body paddleBody2 = world.createBody(paddleDef2);
    paddleBody2.setUserData(5);             

    PolygonShape paddleShape2 = new PolygonShape();
    paddleShape2.setAsBox(3.0f, 15.0f); //half-width and half-height

    FixtureDef paddleFD2 = new FixtureDef();
    paddleFD2.shape = paddleShape2;
    paddleFD2.density = 10.0f;
    paddleFD2.friction = 0.0f;
    paddleFD2.restitution = 0.1f;

    paddleBody2.createFixture(paddleFD2);

    paddleShape2.dispose();

    paddleBody2.setLinearVelocity(0.0f, 0.0f); // Move nowhere at a rate of x = 0.0f, y = 0.0f meters per second
    /**end paddle2**/