How do I remove Sprites when they go on a specific position?

1.1k views Asked by At

My Sprite are spawned at a random time, after being spawned the the move upward until they get on a certain position then they should be removed. That's what I've been trying to do but I always get an error.

//this method is called at random time
 public void newEnemy(){
        Sprite enemy= Pools.obtain(Sprite.class);
        enemy.set(enemySpr);
        enemy.setPosition(200,150);
        enemies.add(enemy);
    }



//removing the enemy
 while (enemyIterator.hasNext()){
  Sprite nextEnemy=enemyIterator.next();//<--error here,this is line 66  
           if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
               removeEnemy(nextEnemy);
           }
       }



//removeEnemy method
public void removeEnemy(Sprite sprite){
        enemies.remove(sprite);
        Pools.free(sprite);
    }



//this is the error there I get:

Exception in thread "LWJGL Application" java.util.ConcurrentModificationException
   at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
   at java.util.ArrayList$Itr.next(ArrayList.java:851)
   at com.dreamroad.savethetree.EnemyClass.update(EnemyClass.java:66)
   at com.dreamroad.savethetree.MyGdxGame.render(MyGdxGame.java:51)
   at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
   at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)

Process finished with exit code 0

I think this is the reason why I get the error, but I'm not sure:

public void draw(SpriteBatch batch){
        for(Sprite drawEnemy:enemies) {    //enemies is the ArrayList
            drawEnemy.draw(batch);
            drawEnemy.translateY(deltaTime * movement);
        }
    }
2

There are 2 answers

4
Phil Anderson On BEST ANSWER

As Subler says, the problem here is that you're trying to remove something from a list at the same time as iterating over it.

However, there's an easier solution. Simply call remove() on the iterator. This will remove the iterator's current element.

//removing the enemy
while (enemyIterator.hasNext()) {

    Sprite nextEnemy = enemyIterator.next();
    if(enemySpr.getY() + enemySpr.getHeight() >= treeObj.treeSpr.getY()) {
        enemyIterator.remove();
        Pools.free(nextEnemy);
    }
}
0
Subler On

The problem is that youre trying to remove something in a list you're currently iterating over, the thing i've always done in a situation like this is create an extra list which holds the Sprites that should be deleted, and then delete them after iterating over the list (or, at the end of your update method, or something like that)

A short code sample that illustrates my idea:

//removing the enemy
//Initialize a list to store the sprites to be removed
List<Sprite> toBeRemovedSprites = new ArrayList<Sprite>();
while (enemyIterator.hasNext()){
    Sprite nextEnemy=enemyIterator.next(); //I get the error here..<--
    if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
        removeEnemy(nextEnemy);
        toBeRemovedSprites.add(nextEnemy);
    }
}
//Remove the sprites that should be deleted, after iterating over the list
for(Sprite s : toBeRemovedSprites){
    enemies.remove(s);
}



//removeEnemy method
public void removeEnemy(Sprite sprite){
    //Remove this line that removes the sprite from the list
    //enemies.remove(sprite);
    Pools.free(sprite);
}

Another thing you could do is just to use the remove function of the iterator, imagine it could look something like this:

//removing the enemy
while (enemyIterator.hasNext()){
    Sprite nextEnemy=enemyIterator.next(); //I get the error here..<--
    if(enemySpr.getY()+enemySpr.getHeight()>=treeObj.treeSpr.getY()){
        removeEnemy(nextEnemy, enemyIterator);
    }
}



//removeEnemy method
public void removeEnemy(Sprite sprite, Iterator<Sprite> enemyIterator){
    //Change the line to remove using the iterator
    //enemies.remove(sprite);
    enemyIterator.remove();
    Pools.free(sprite);
}