충돌이 발생할 때 box2d 바디를 제거하는 방법?


10

나는 여전히 자바와 안드로이드 프로그래밍에 익숙하지 않으며 충돌이 발생할 때 객체를 제거하는 데 많은 문제가 있습니다. 웹을 둘러보고 충돌 감지 (접촉 리스너) 중에 BOX2D 바디 제거를 처리해서는 안되며 객체를 배열 목록에 추가하고 바디의 사용자 데이터 섹션에서 변수를 삭제 여부를 설정해야합니다. 업데이트 처리기에서 제거 작업 그래서 나는 이것을했다 : 먼저 두 개의 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이 발생하므로 업데이트 핸들러를 추가하는 올바른 방법은 무엇이며 어디에 추가해야합니까? 이 작업을 수행하는 다른 조언은 좋을 것입니다. 미리 감사드립니다.

답변:


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 ++에서 인터넷을 통해 해결책을 찾았습니다! 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 () 메소드는 스프라이트와 해당 바디를 제거 할 준비가되었는지 확인합니다.


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();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.