发生碰撞时如何删除box2d实体?


10

我对Java和android编程还是很陌生,遇到碰撞时要移除对象有很多麻烦。我在网上四处张望,发现在碰撞检测(接触侦听器)期间,我绝不应该删除BOX2D主体,而应将对象添加到arraylist并在主体的“用户数据”部分中设置一个变量以删除或不删除并处理更新处理程序中的删除操作。因此,我这样做了:首先,我定义了两个ArrayList,一个用于面部,一个用于主体:

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

然后,当我创建一个面并将该面连接到其主体时,我将其添加到其ArrayList中,如下所示:

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);

现在,我在onloadscene中添加了一个联系人监听器和一个更新处理程序,如下所示:

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) {

}
});

我的计划是通过检查主体的用户数据部分中的变量来检测哪个主体在联系人侦听器中发生冲突,并在数组列表中获取它们的编号,最后使用更新处理程序删除这些主体。

问题是:我是否正确使用了arraylist?如何向用户数据中添加变量(请提供代码)。我尝试在此更新处理程序中删除主体,但仍会抛出NullPointerException异常,因此添加更新处理程序的正确方法是什么,应该在哪里添加。任何其他建议可以做到这一点。提前致谢。

Answers:


7

在JBox2d中,要在正确的时间删除:

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.
}   

使用body.getUserData()body.setUserData()读写userDataBody


1

一周前我遇到了类似的问题,但是在C ++中,我可以通过Internet找到解决方案!这是Box2D world-> Step之后使用的方法代码,它可以正常工作:

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;
}

祝您好运,并度过愉快的一天。希望您能在此帮助下节省时间;)

编辑:方法sprite-> is_killed()检查sprite及其物理身体是否已准备好移除。


1
-1,问题与Java有关,这是一项任务,在不同的语言中完全不同。它也不是很好的C ++-尝试使用std :: set或std :: unordered_set,我也将使用STL算法来处理破坏,或者至少要更好地处理循环条件。

1

如果要添加 isDead在用户数据中标记,只需在创建时将其添加到您设置为用户数据的任何位置即可Body

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

然后在 endContact()标记要死亡的尸体为死尸:

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

然后,请确保您删除中的死物update()。在PhysicsWorld更新时不要这样做:

foreach(GameObject go : gameObjects) {
    if(go.isDead()) {
         destroyGameObject(go);
         go.onDestroyed();
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.