Java LibGDX阻止body获取以前删除的body的属性

Java LibGDX阻止body获取以前删除的body的属性,java,libgdx,box2d,Java,Libgdx,Box2d,为清晰起见,请观看视频: 我正在制作我的第一个LibGDX游戏,我在销毁和创建尸体方面遇到了困难。我一直在使用这个片段(因为它似乎无处不在)来移除尸体: private void sweepDeadBodies() { for (Iterator<Body> iter = tmpBodies.iterator(); iter.hasNext();) { Body body = iter.next(); if (body != null) {

为清晰起见,请观看视频:

我正在制作我的第一个LibGDX游戏,我在销毁和创建尸体方面遇到了困难。我一直在使用这个片段(因为它似乎无处不在)来移除尸体:

private void sweepDeadBodies() {
    for (Iterator<Body> iter = tmpBodies.iterator(); iter.hasNext();) {
        Body body = iter.next();
        if (body != null) {
            Entity data = (Entity) body.getUserData(); //Just the bodies data
            if (data.isFlaggedForDelete) {
                iter.remove();
                world.destroyBody(body);
                body.setUserData(null);
                body = null;
            }
        }
    }
}
记录错误(我只能找到类似堆栈跟踪的东西) (TestControls是我们正在使用的屏幕)

设置删除标志的世界联系人侦听器:

    world.setContactListener(new ContactListener() {
        @Override
        public void beginContact(Contact contact) {
        }

        @Override
        public void endContact(Contact contact) {
            if (contact.getFixtureA().getFilterData().categoryBits == Entities.CATEGORY_PLAYER_PROJECTILE
                    && contact.getFixtureB().getFilterData().categoryBits == Entities.CATEGORY_ENEMY) {
                ((Entity) contact.getFixtureA().getBody().getUserData()).isFlaggedForDelete = true;
                ((Entity) contact.getFixtureB().getBody().getUserData())
                        .damage(((Entity) contact.getFixtureA().getBody()
                                .getUserData()).damage);
            }
            if (contact.getFixtureA().getFilterData().categoryBits == Entities.CATEGORY_ENEMY
                    && contact.getFixtureB().getFilterData().categoryBits == Entities.CATEGORY_PLAYER_PROJECTILE) {
                ((Entity) contact.getFixtureB().getBody().getUserData()).isFlaggedForDelete = true;
                ((Entity) contact.getFixtureA().getBody().getUserData())
                        .damage(((Entity) contact.getFixtureB().getBody()
                                .getUserData()).damage);
            }
        }

        @Override
        public void preSolve(Contact contact, Manifold oldManifold) {
        }

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

你必须把激光器排成一排。他们正在离开范围并被摧毁,但尸体仍然活着。box2d回收车身,因此可能会导致问题。像那样在渲染中创建它们也很糟糕。对于生命周期短的任何东西,都应该使用池

以任何方式触摸弃置的尸体都会炸毁游戏,所以最好不要在游戏中弃置尸体

我最近发布了libgdx/box2d游戏,该游戏广泛使用池。您可以在查看代码

还有endContact(),请将其清理干净。它不可能被阅读。大概是这样吧

@Override
public void endContact(Contact contact) {
    Fixture fA = contact.getFixtureA();
    Fixture fB = contact.getFixtureB();
    if (isPlayerProjectile(fA) && isEnemy(fB)) {
        Entity projectile = (Entity) contact.getFixtureA().getBody().getUserData();
        Entity enemy = (Entity) contact.getFixtureB().getBody().getUserData();
        solveProjectileEnemyContact(projectile, enemy);
    } else if (isPlayerProjectile(fB) && isEnemy(fA)) {
        Entity projectile = (Entity) contact.getFixtureB().getBody().getUserData();
        Entity enemy = (Entity) contact.getFixtureA().getBody().getUserData();
        solveProjectileEnemyContact(projectile, enemy);
    }
}

private boolean isPlayerProjectile(Fixture fixture){
    return fixture.getFilterData().categoryBits == Entities.CATEGORY_PLAYER_PROJECTILE;
}

private boolean isEnemy(Fixture fixture){
    return fixture.getFilterData().categoryBits == Entities.CATEGORY_ENEMY;
}

private void solveProjectileEnemyContact(Entity projectile, Entity enemy){
    projectile.isFlaggedForDelete = true;
    enemy.damage(projectile.damage);
}

在过去的两天里,我也遇到了同样的问题

这是一个简单的bug,我有一个当前显示的实体的ArrayList。如果发生碰撞,我会像你一样设置一面旗帜。后来,我运行了我的实体ArrayList并删除了每个被标记的实体体——但不是实体本身

这是我的删除代码。它对我有效,我希望它对你也有效

CopyOnWriteArrayList<Entity> entities = new CopyOnWriteArrayList<Entity>();

public void deleteEntities() {
    for(Entity entity: entities){
        Body body = entity.getBody();
        if (body != null) {
            EntityData data = (EntityData) body.getUserData();
            if (data.isFlaggedForDelete()) {
                final Array<JointEdge> list = body.getJointList();
                //delete all joints attached
                while (list.size > 0) {
                    myWorld.getWorld().destroyJoint(list.get(0).joint);
                }
                //nullify everything, remove the entity from entities and destroy the body
                body.setUserData(null);
                myWorld.getWorld().destroyBody(body);
                entities.remove(entity);
                body = null;                    
            }
        }
    }
}
CopyOnWriteArrayList实体=新建CopyOnWriteArrayList();
公共实体(){
for(实体:实体){
Body=entity.getBody();
if(body!=null){
EntityData data=(EntityData)body.getUserData();
if(data.isFlaggedForDelete()){
最终数组列表=body.getJointList();
//删除所有附着的关节
而(list.size>0){
myWorld.getWorld().destroyJoint(list.get(0.joint));
}
//取消所有内容,从实体中移除实体并销毁实体
body.setUserData(空);
myWorld.getWorld().destroyBody(body);
实体。移除(实体);
body=null;
}
}
}
}
另外,请确保不要过早处理()!也可能是个问题


我希望这是有帮助的:-)

我知道这个问题已经很老了,但我想分享一下我的经验,这个错误与选择的答案没有帮助

因此,对于仍在经历此问题的任何人,我就是这样解决的:

我没有随机创建和删除我的身体,而是用两种方法创建和删除了所有创建和删除:

    //CREATE ALL
public void createAll(){    
    if(!world.isLocked()){ //KEY FACTOR
        if(createEnemy){
            createEnemy();
        }
        if(createBullet){
            createBullet();     
        }
    }   
}
删除:

    //get rid of all bodies  (toBeDeleted is an Array<Body>)
public void sweepDeadBodies() {
    if(!world.isLocked()){ // KEY FACTOR
    Array<Body> wB = getBodies();   
       for (Body body : wB) {         
         if(body!=null && toBeDeleted.contains(body, false)) {
                  body.setUserData(null);
                  world.destroyBody(body);
                  toBeDeleted.removeValue(body, false);
         }

       }
    }          
}
最后,我的敌人()

还有我的createBullet():

在我标记删除后,所有待删除的实体都在那里,如下所示:

((UserData) enemy.getBody().getUserData()).isFlaggedForDelete = true;
并添加如下内容:

  if(((UserData)body.getUserData()).isFlaggedForDelete){
        toBeDeleted.add(body);
    }
在我的更新方法


我希望这对某人有帮助。基本上,我的错误是在没有检查世界是否被锁定的情况下创建/销毁尸体,我通过调用!世界。已锁定()

首先,除了设备非关闭的堆栈跟踪之外,是否还有另一个堆栈跟踪被输出?这通常是当你运行游戏的窗口突然崩溃时出现的。其次,在销毁主体的userData之前,应该尝试将其设置为null。最后,您能给出为要销毁的实体集设置markedForDelete的代码吗?谢谢您的回复。我添加了请求的代码。我事先将用户数据设置为null,但仍然得到相同的错误。哇。你的比赛(显然)比我现在的水平有了飞跃。您能告诉我开始查看哪些文件的正确方向吗?请注意,destroyBody也会自动销毁所有关联的关节,因此无需手动执行此操作
    //get rid of all bodies  (toBeDeleted is an Array<Body>)
public void sweepDeadBodies() {
    if(!world.isLocked()){ // KEY FACTOR
    Array<Body> wB = getBodies();   
       for (Body body : wB) {         
         if(body!=null && toBeDeleted.contains(body, false)) {
                  body.setUserData(null);
                  world.destroyBody(body);
                  toBeDeleted.removeValue(body, false);
         }

       }
    }          
}
    @Override
public void draw() {
    super.draw();

    glyphLayout.setText(scoreFont, score);

    //Do all my deleting and creating after the world.step !!! VERY IMPORTANT!!!
    sweepDeadBodies();
    removeEmtpyActors(); //I use actors as containers for the body, so here i loop though them all and nullify them
    createAll();
    renderer.render(world, camera.combined);

}
  private void createEnemy() {
        Enemy enemy= new Enemy(WorldUtils.createEnemy(world));
        ((UserData) enemy.getBody().getUserData()).isFlaggedForDelete = false;
        addActor(enemy);
        addGameActor(enemy); //again this is just for me, you might be using entities or something else
        createEnemy = false;
    }
public void createBullet(){
        Bullet bullet = new Bullet(WorldUtils.createBullet(world));
        ((UserData) bullet.getBody().getUserData()).isFlaggedForDelete = false;
        addActor(bullet);
        addGameActor(bullet);
        bullet.fire();  //just adds a linear impulse
        createBullet= false;
    }
((UserData) enemy.getBody().getUserData()).isFlaggedForDelete = true;
  if(((UserData)body.getUserData()).isFlaggedForDelete){
        toBeDeleted.add(body);
    }