Box2D Null Fixture in contact handler after deletion - java

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.

Related

Ashley ECS IteratingSystem not processing entity family

Somehow I cannot get the IteratingSystem to work. In the update I double check if there are entities, it returns more then 0. But that should mean that processEntity gets called on those but it never runs.
//...
import net.madmenyo.teststuff.AshleyTest.components.MovementComponent;
import net.madmenyo.teststuff.AshleyTest.components.PositionComponent;
//...
public class MovementSystem extends IteratingSystem {
private ComponentMapper<PositionComponent> pm;
private ComponentMapper<MovementComponent> mm;
public MovementSystem () {
super(Family.all(PositionComponent.class, MovementComponent.class).get());
pm = ComponentMapper.getFor(PositionComponent.class);
mm = ComponentMapper.getFor(MovementComponent.class);
}
#Override
public void processEntity (Entity entity, float deltaTime) {
System.out.println("Process moveSystem");
PositionComponent position = pm.get(entity);
MovementComponent movement = mm.get(entity);
position.x += movement.velocityX * deltaTime;
position.y += movement.velocityY * deltaTime;
}
#Override
public void update(float deltaTime) {
Engine engine = getEngine();
int count = engine.getEntitiesFor(Family.all(PositionComponent.class, MovementComponent.class).get()).size();
}
}
Afaik, for each count in the update method it should run ProcessEntity each time the engine is updated. Since update is called the engine is updated and since count > 0 it should be processing entities, yet it is never called. By inspecting the engine during runtime it also contains multiple entities for the family I define.
processEntity(...) is called by the parent update method which I wasn't calling. Easy fix once I looked at it again, I just leave it here in case.
#Override
public void update(float deltaTime) {
super.update(deltaTime); // <-- call parent update
}

IStructuredSelection: Use the same Selection in 2 different Views

I'm using a TreeViewer with a list of customers. I added a DoubleClickListener to the TreeViewer.
this.treeViewer.addDoubleClickListener(new IDoubleClickListener() {
#Override
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection thisSelection = (IStructuredSelection) event
.getSelection();
Object selectedNode = thisSelection.getFirstElement();
if (selectedNode instanceof ICustomer) {
ICustomer customer = (ICustomer) selectedNode;
selectionService.setSelection(customer);
perspective = (MPerspective) modelService
.find("de.checkpoint.rinteln.carlofon.perspective.customer",
app);
}
if (perspective != null) {
partService.switchPerspective(perspective);
}
}
});
In the Customer-Perspective, I've got 2 Views, which use the selected customer to load his data(orders and reminders) from the DB.
In the Customer-View, everything works just fine. But once i move on the next view(Reminder or Order) the selection list Null, which I don't get.
#Inject
void setSelection(
#Optional #Named(IServiceConstants.ACTIVE_SELECTION) ICustomer customer) {
if (customer != null) {
idText.setText("" + customer.getCustomerId());
customerNameText
.setText(customer.getFirstname() + " " + customer.getLastname());
steetText.setText(customer.getStreet());
cityText.setText(customer.getCity());
steetCodeText.setText("" + customer.getCityCode());
} else {
// TODO Clear View!
}
}
And in the Reminder-View (in the same perspective as the Customer-View), the selected Customer is Null
#Inject
void setSelection(
#Optional #Named(IServiceConstants.ACTIVE_SELECTION) ICustomer customer) {
if (customer != null) {
super.treeViewer.setInput(service.loadAll());
} else {
// TODO Clear View!
}
}
Which lead to my question, do i miss something? Am I not supposed to use the same selection in different views?
I must add, that both views extend an AbstractView in which the IDoubleClickListener is implemented.

Need to know when collision is begin and end box2d

public class Contact implements ContactListener {
#Override
public void beginContact(Contact contact) {
Fixture fa = contact.getFixtureA();
Fixture fb = contact.getFixtureB();
if (fa.getFilterData().categoryBits==16){
((Gamescreen)fa.getUserData()).starttouch(fa,fb);
}
#Override
public void endContact(Contact contact) {
Fixture fa = contact.getFixtureA();
Fixture fb = contact.getFixtureB();
if (fa.getFilterData().categoryBits==16)
{
((Gamescreen)fa.getUserData()).endtouch();
}
This code works fine when there is just one object to touch but some time i need to make like tow object beside of each others.
Like when the player walk on 2 objects (without jumping) beside each others the second method (endcontact) called but the first method (begincontact) does not get call again.
If I understood correctly, then this link may be what you're looking for:
http://www.iforce2d.net/b2dtut/collision-callbacks
It's C++, but you can see example implementation of collision callback for a pair of objects:
void BeginContact(b2Contact* contact) {
//check if fixture A was a ball
void* bodyUserData = contact->GetFixtureA()->GetBody()->GetUserData();
if ( bodyUserData )
static_cast<Ball*>( bodyUserData )->startContact();
//check if fixture B was a ball
bodyUserData = contact->GetFixtureB()->GetBody()->GetUserData();
if ( bodyUserData )
static_cast<Ball*>( bodyUserData )->startContact();
}
Additionally, you don't save true/false if contact started, but number of contacts:
//new implementation for contact state change
void startContact() { m_numContacts++; }
void endContact() { m_numContacts--; }

How do I keep a body unrendered in Libgdx Box2d?

I couldn't find the answer anywhere and I am starting to doubt if that's possible. How can I keep a body in LIbgdx "Invisble"? So that it will keep interacting with everything and act like a regular body but just won't be rendered
You can create your own Box2dDebugRenderer and override renderBody method.
class MyBox2dRenderer extends Box2DDebugRenderer {
private ArrayList<Body> notRenderingBodies; // array of vodies that you dont want to render
public MyBox2dRenderer(ArrayList<Body> notRenderingBodies) {
super();
this.notRenderingBodies = notRenderingBodies;
}
#Override
protected void renderBody(Body body) {
for (Body b : notRenderingBodies) { // loop through all bodies in array
if (b == body){ // if given body equals by reference to one from list than return
return;
}
}
super.renderBody(body);
}
public ArrayList<Body> getNotDenderingBodies() {
return notRenderingBodies;
}
public void setNotDenderingBodies(ArrayList<Body> notDenderingBodies) {
this.notRenderingBodies = notDenderingBodies;
}
}

JBox2D Body Was There, Now it's null?

A strange bug I can't track down. I've implemented a ContactListener class for handling collisions in my Android game. In the beginContact(Contact arg0) method I can see that the two bodies in arg0 is there, and pushed onto a stack. Right after calling world.step() I run my own handleCollisions() method, where I pop off the Contact objects and do some game logic. However, occasionally when I pop off a Contact, one or both of its bodies are null.
The Contact goes in the stack with its bodies there, but it comes out with null bodies. I don't know why this is occurring, and more importantly, I can't find when this is occurring. To my knowledge, none of my code elsewhere is removing the bodies, but then again there could be side effects I'm unaware of. It doesn't help that this doesn't always happen. Typically it occurs when there's several collisions occurring.
Anyone have any ideas on what might remove the bodies? Or, does anyone know of a way to track the bodies to determine when they become null?
Below is some code which may or may not be helpful:
public class ConcreteContactListener implements ContactListener
{
private Stack<Contact> contacts;
public ConcreteContactListener()
{
contacts = new Stack<Contact>();
}
#Override
public void beginContact(Contact arg0)
{
contacts.push(arg0);
System.out.println("push: " + arg0.m_fixtureA.m_body);
}
public int handleCollisions(ArrayList<Ball> balls, World world, ArrayList<Ball> smears, SoundEffects sfx, Combos combos)
{
int score = 0;
while (!contacts.isEmpty())
{
Contact contact = contacts.pop();
System.out.println("Contact: " + contact.m_fixtureA.m_body);
int a = -1;
int b = -1;
for (int i = 0; i < balls.size(); i++)
{
System.out.println("Ball: " + balls.get(i).getBody());
if (contact.m_fixtureA.m_body.equals(balls.get(i).getBody()))
a = i;
else if (contact.m_fixtureB.m_body.equals(balls.get(i).getBody()))
b = i;
}
...
}
}
Contacts are pooled and re-used, so I would not recommend using this approach. Instead I would buffer only the information you need (which is probably the two bodies). The jbox2d testbed handles it this way:
First we have a contact point:
public class ContactPoint {
public Fixture fixtureA;
public Fixture fixtureB;
public final Vec2 normal = new Vec2();
public final Vec2 position = new Vec2();
public PointState state;
}
And then we listen like so:
public void beginContact(Contact contact) {
}
public void endContact(Contact contact) {
}
public void postSolve(Contact contact, ContactImpulse impulse) {
}
private final PointState[] state1 = new PointState[Settings.maxManifoldPoints];
private final PointState[] state2 = new PointState[Settings.maxManifoldPoints];
private final WorldManifold worldManifold = new WorldManifold();
public void preSolve(Contact contact, Manifold oldManifold) {
Manifold manifold = contact.getManifold();
if (manifold.pointCount == 0) {
return;
}
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Collision.getPointStates(state1, state2, oldManifold, manifold);
contact.getWorldManifold(worldManifold);
for (int i = 0; i < manifold.pointCount
&& pointCount < MAX_CONTACT_POINTS; i++) {
ContactPoint cp = points[pointCount];
cp.fixtureA = fixtureA;
cp.fixtureB = fixtureB;
cp.position.set(worldManifold.points[i]);
cp.normal.set(worldManifold.normal);
cp.state = state2[i];
++pointCount;
}
}
This would probably be a bit overkill for your purposes, as it executes this logic for every single contact. Instead you can use the beginContact() and endContact() methods and buffer something a little more optimized with your game, like just storing the colliding bodies or something.

Categories