11
\$\begingroup\$

I’m still new to java and android programming and I am having so much trouble Removing an object when collision happens. I looked around the web and found that I should never handle removing BOX2D bodies during collision detection (a contact listener) and I should add my objects to an arraylist and set a variable in the User Data section of the body to delete or not and handle the removing action in an update handler. So I did this: First I define two ArrayLists one for the faces and one for the bodies:

ArrayList<Sprite> myFaces = new ArrayList<Sprite>();
ArrayList<Body> myBodies = new ArrayList<Body>();

Then when I create a face and connect that face to its body I add them to their ArrayLists like this:

face = new AnimatedSprite(pX, pY, pWidth, pHeight, this.mBoxFaceTextureRegion);
Body BoxBody = PhysicsFactory.createBoxBody(mPhysicsWorld, face, BodyType.DynamicBody, objectFixtureDef);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(face, BoxBody, true, true));

myFaces.add(face);
myBodies.add(BoxBody);

now I add a contact listener and an update handler in the onloadscene like this:

this.mPhysicsWorld.setContactListener(new ContactListener() {
private AnimatedSprite face2;
@Override
public void beginContact(final Contact pContact) {
}
@Override
public void endContact(final Contact pContact) {
}
@Override
public void preSolve(Contact contact,Manifold oldManifold) {

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



scene.registerUpdateHandler(new IUpdateHandler() {


@Override
public void reset() { }

@Override
public void onUpdate(final float pSecondsElapsed) {

}
});

My plan is to detect which two bodies collided in the contact listener by checking a variable from the user data section of the body, get their numbers in the array list and finally use the update handler to remove these bodies.

The questions are: Am I using the arraylist correctly? How to add a variable to the User Data (the code please). I tried removing a body in this update handler but it still throws me NullPointerException , so what is the right way to add an update handler and where should I add it. Any other advices to do this would be great. Thanks in advance.

\$\endgroup\$

3 Answers 3

7
\$\begingroup\$

In JBox2d, to remove at the correct time:

public class Main
{
    World world;
    ...

    public void update() //your game loop
    {
        ... //do all actual update loop stuff, including detection of collision/death/destruction
        for (Entity entity : manager.entitiesToRemove)
        {
            world.destroyBody(entity.body); //this might be all you need -- adapt to your own purposes. but you will still need a list such that you remove only at the end of each tick.
        }

        manager.entitiesToRemove.clear();
    }
}

public class Entity
{
    Body body; //body representing this Entity
    EntityManager manager; //set ref via Entity constructor
    ...

    //Call from your contact listener when the entity expires
    //body.userData is set to the Entity representing that body
    //so you can get access to the Entity from the Body, as vice versa.
    public void die()
    {
        manager.removeEntity(this);
    }
    ...
}   

public class EntityManager
{
    public List<Entity> entities = new ArrayList<Entity>(); //extant entities
    public List<Entity> entitiesToAdd = new ArrayList<Entity>(); //forthcoming entities
    public List<Entity> entitiesToRemove = new ArrayList<Entity>(); //erstwhile entities <-- the important one for you.
    ...
    public void remove()
    {
        if (!stage.entitiesToRemove.contains(entity))
            stage.entitiesToRemove.add(entity);
            //or just use a Set<Entity>, as dual additions are implicitly prevented.
    }
    ...
    //also add(), and other utility functions for managing entities.
}   

Use body.getUserData() and body.setUserData() to read and write userData on the Body.

\$\endgroup\$
0
2
\$\begingroup\$

If you want to add a isDead flag to your user data, just add it to whatever you set as your user data when you create the Body.

GameObject box = new GameObject(face, boxBody);
boxBody.setUserData(box);

Then in endContact() flag the bodies you want to be dead as dead:

if( a collision happens ) {
    ((GameObject) bodyA.getUserData()).setDead(true);
    ((GameObject) bodyB.getUserData()).setDead(true);
}

Then make sure you remove the dead objects in update(). Don't do this while the PhysicsWorld is updating:

foreach(GameObject go : gameObjects) {
    if(go.isDead()) {
         destroyGameObject(go);
         go.onDestroyed();
    }
}
\$\endgroup\$
1
\$\begingroup\$

I have similar problem week ago but in C++ and I find solution over the internet! Here is method code that I am using after Box2D world->Step and it works:

void physics::clean_up() {
std::vector<b2Body *> to_nuke;

b2Body * body = _world->GetBodyList();
for(; body; body = body->GetNext()) {
    gx::sprite * sprite = (gx::sprite *)body->GetUserData();
    if(sprite->is_killed()) {
        to_nuke.push_back(body);
    }
}

std::sort(to_nuke.begin(), to_nuke.end());
// destroying, but skip duplicates!
uint i = 0;
uint size = to_nuke.size();
while(i < size) {
    b2Body * b = to_nuke[i++];
    while(i < size && to_nuke[i] == b) {
        ++i;
    }
    _world->DestroyBody(b);
    b = 0;
}

Good luck with porting and have a nice day. I hope you will save your time with this help ;)

edit: the method sprite->is_killed() check if sprite and its physical body is ready to remove.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ -1, the question concerns Java and this is a task that is pretty different in different languages. It's also not very good C++ - try using an std::set or std::unordered_set, and I'd use an STL algorithm to handle the destruction as well, or at least a better loop condition. \$\endgroup\$
    – user744
    Commented Sep 6, 2011 at 17:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .