I am using Libgdx's box2d implementation.
I am encountering a null pointer error after I delete a body from the world. I've tracked the problem down to my contact listener, where I am testing the fixture's filter against the other fixture to see if I should process the collision. The problem is that one of the fixtures is null. Initially you would think, okay so only process the collision for the non-null fixture, but if I don't know what the fixture was that ended contact, it becomes impossible to know what is and is not contacting the non-null fixture.
Before I get into the code, I promise that making the actual world.destroyBody(body) call outside of the physics step by adding the body to a queue to be processed later. Additionally the body gets queued in the update loop, which happens before the world.step()
(Note: Entities are basically wrappers for bodies)
Here is the main update loop
@Override
public void render() {
processDestroyQueue();
sm.update(); //Calls entity update functions, where the entity is added to the q
camera.update();
//Step
world.step(STEP, 6, 2); //Step == 1/60f
//... removed rendering stuff
}
Here is the add to queue function and processDestroyQueue()
public void destroy(Entity ent){
destroyQueue.add(ent);
}
private void processDestroyQueue(){
Entity ent;
while((ent = destroyQueue.poll()) != null){
world.destroyBody(ent.body());
ent.dispose();
entities.remove(ent);
}
}
Finally here is the contact handler
public class ContactHandler implements ContactListener {
@Override
public void beginContact(Contact contact) {
Fixture fixA = contact.getFixtureA();
Fixture fixB = contact.getFixtureB();
parseContact(true, fixA, fixB, contact);
}
@Override
public void endContact(Contact contact) {
Fixture fixA = contact.getFixtureA();
Fixture fixB = contact.getFixtureB();
parseContact(false, fixA, fixB, contact);
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
// TODO Auto-generated method stub
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
// TODO Auto-generated method stub
}
public void parseContact(boolean begin, Fixture fixA, Fixture fixB, Contact contact){
System.out.println("FixtureA: " + fixA);
System.out.println("FixtureB: " + fixB);
if( (fixA.getFilterData().categoryBits & fixB.getFilterData().maskBits) != 0 ){
sendContact(begin, fixA, fixB, contact);
sendContact(begin, fixB, fixA, contact);
}else if( (fixB.getFilterData().categoryBits & fixA.getFilterData().maskBits) != 0 ){
sendContact(begin, fixA, fixB, contact);
sendContact(begin, fixB, fixA, contact);
}
}
public void sendContact(boolean begin, Fixture fixA, Fixture fixB, Contact contact){
Object dataA = fixA.getUserData();
Object dataB = fixB.getUserData();
if(dataA instanceof FixtureData && dataB instanceof FixtureData){
FixtureData fixtureDataB = (FixtureData)dataB;
FixtureData fixtureDataA = (FixtureData)dataA;
fixtureDataA.contact(fixB, contact, begin);
fixtureDataB.contact(fixA, contact, begin);
}
}
}
Lastly the error:
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.gearworks.game.ContactHandler.parseContact(ContactHandler.java:42)
at com.gearworks.game.ContactHandler.endContact(ContactHandler.java:24)
at com.badlogic.gdx.physics.box2d.World.endContact(World.java:903)
at com.badlogic.gdx.physics.box2d.World.jniDestroyBody(Native Method)
at com.badlogic.gdx.physics.box2d.World.destroyBody(World.java:322)
at com.gearworks.Client.processDestroyQueue(Client.java:189)
at com.gearworks.Client.render(Client.java:118)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:206)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
From what it looks like to me Box2D simply erases the fixture and then dispatches its end contact event. I need That fixture to be in the end contact even so that I know which fixture has completed its contact. Is my implementation wrong? Or is this just how box2D works and I need to figure out some other method?
It was indeed a bug in libgdx:
https://github.com/libgdx/libgdx/issues/1381
https://github.com/libgdx/libgdx/pull/1837
I think you just need a newer version of the source.
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.