Bagaimana cara menghapus tubuh box2d ketika tabrakan terjadi?

10

Saya masih baru untuk pemrograman java dan android dan saya mengalami begitu banyak masalah Menghapus objek ketika terjadi tabrakan. Saya melihat-lihat web dan menemukan bahwa saya seharusnya tidak pernah menangani menghapus badan BOX2D selama deteksi tabrakan (pendengar kontak) dan saya harus menambahkan objek saya ke daftar array dan mengatur variabel di bagian Data Pengguna tubuh untuk dihapus atau tidak dan menangani tindakan menghapus dalam penangan pembaruan. Jadi saya melakukan ini: Pertama saya mendefinisikan dua Daftar Array untuk wajah dan satu untuk tubuh:

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

Lalu ketika saya membuat wajah dan menghubungkan wajah itu ke tubuhnya, saya menambahkan mereka ke ArrayLists mereka seperti ini:

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

sekarang saya menambahkan pendengar kontak dan pengendali pembaruan di onloadscene seperti ini:

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

}
});

Rencana saya adalah untuk mendeteksi dua badan yang bertabrakan di pendengar kontak dengan memeriksa variabel dari bagian data pengguna dari tubuh, mendapatkan nomor mereka dalam daftar array dan akhirnya menggunakan penangan pembaruan untuk menghapus badan-badan ini.

Pertanyaannya adalah: Apakah saya menggunakan daftar array dengan benar? Bagaimana cara menambahkan variabel ke Data Pengguna (kodenya). Saya mencoba menghapus sebuah body di handler pembaruan ini tetapi masih melempar saya NullPointerException, jadi apa cara yang tepat untuk menambahkan handler pembaruan dan di mana saya harus menambahkannya. Nasihat lain untuk melakukan ini akan bagus. Terima kasih sebelumnya.

Ayham
sumber

Jawaban:

7

Di JBox2d, untuk menghapus pada waktu yang tepat:

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

Gunakan body.getUserData()dan body.setUserData()untuk membaca dan menulis userDatadi Body.

Insinyur
sumber
1

Saya memiliki masalah yang sama minggu lalu tetapi di C ++ dan saya menemukan solusi melalui internet! Ini adalah kode metode yang saya gunakan setelah Box2D world-> Step dan berfungsi:

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

Semoga berhasil dengan porting dan semoga harimu menyenangkan. Saya harap Anda akan menghemat waktu Anda dengan bantuan ini;)

sunting: metode sprite-> is_killed () periksa apakah sprite dan tubuh fisiknya siap dihapus.

Gregory
sumber
1
-1, pertanyaannya menyangkut Java dan ini adalah tugas yang cukup berbeda dalam bahasa yang berbeda. Ini juga bukan C ++ yang sangat bagus - coba gunakan std :: set atau std :: unordered_set, dan saya akan menggunakan algoritma STL untuk menangani penghancuran juga, atau setidaknya kondisi loop yang lebih baik.
1

Jika Anda ingin menambahkan isDeadbendera ke data pengguna Anda, tambahkan saja ke apa pun yang Anda tetapkan sebagai data pengguna saat membuat Body.

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

Kemudian di endContact()bendera tubuh Anda ingin mati sebagai mati:

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

Kemudian pastikan Anda menghapus benda mati di update(). Jangan lakukan ini saat PhysicsWorld memperbarui:

foreach(GameObject go : gameObjects) {
    if(go.isDead()) {
         destroyGameObject(go);
         go.onDestroyed();
    }
}
skyuzo
sumber