0

I am making a 2D java game based on Space Invaders. In my Game class I have these 3 fields:

//enemies left to kill
private LinkedList<Enemy> enemiesLeft = new LinkedList<Enemy>(); 
//enemies killed
private LinkedList<Enemy> enemiesKilled = new LinkedList<Enemy>();
//missiles that have been fired
private LinkedList<Missile> missiles = new LinkedList<Missile>();

In my checkCollision() method I run through each Enemy in the enemiesLeft list and check for collision with each Missile in the missiles list, but it throws a ConcurrentModificationException.

Here is the checkCollision() method:

private void checkCollisions(){
  //make an iterator over enemies
  ListIterator<Enemy> iterEnemies = enemiesLeft.listIterator();   

  //loop through enemies
  while(iterEnemies.hasNext()){
    //error is thrown at below line
    Enemy e = iterEnemies.next();  //current Enemy

    //go through each Missile
    ListIterator<Missile> iterMissiles = missiles.listIterator(); 
    while(iterMissiles.hasNext()){
      Missile m = iterMissiles.next();  //current Missile
      if(e.doesIntersect(m)){           
      //remove Enemy from enemiesLeft and add it to enemiesKilled list
      enemiesKilled.add(enemiesLeft.remove(enemiesLeft.indexOf(e)));
      //remove Missile
      missiles.remove(m);
      }
    }
  }
   updateScore();
}

And this is the error I get:

java.util.ConcurrentModificationException
   at java.util.LinkedList$ListItr.checkForComodification(Unknown Source)
   at java.util.LinkedList$ListItr.next(Unknown Source)
   at Game.checkCollisions(Game.java:168)
   at Game.run(Game.java:197)
   at Game.main(Game.java:279)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
   at java.lang.reflect.Method.invoke(Unknown Source)
   at      edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:272)

The game runs smooth until a collision occurs. Please help me!

Loupi
  • 550
  • 6
  • 14
  • 2
    See this question about [avoiding ConcurrentModificationException](http://stackoverflow.com/questions/223918/iterating-through-a-list-avoiding-concurrentmodificationexception-when-removing) for a discussion of **why** this happens, as well as some options to resolve this problem. – Andrzej Doyle Apr 07 '15 at 10:45

4 Answers4

5

You can use ListIterator's remove() method.

Use below code instead of missiles.remove(m);

iterMissiles.remove();

and same for removing from enemiesLeft.

while(iterMissiles.hasNext()){
  Missile m = iterMissiles.next();  //current Missile
  if(e.doesIntersect(m)){           
  //remove Enemy from enemiesLeft and add it to enemiesKilled list
  enemiesKilled.add(e);
  iterEnemies.remove();

  //remove Missile
  iterMissiles.remove();
  }
}
Naman Gala
  • 4,670
  • 1
  • 21
  • 55
  • thanks this works perfectly! Just one question. If it is possible to say `missiles.remove(m)` and `iterMissiles.remove()` and they both work, why is it not possible to remove enemies through `enemiesLeft.remove(e)`? – Loupi Apr 07 '15 at 10:58
  • You can refer [this](http://stackoverflow.com/questions/223918/iterating-through-a-list-avoiding-concurrentmodificationexception-when-removing). `Iterator.remove` is the only safe way to modify a collection during iteration. – Naman Gala Apr 07 '15 at 11:00
  • If you want to use `missiles.remove(m)`, then you need to follow the steps shown in the answer by @Rawa – Naman Gala Apr 07 '15 at 11:03
0

The problem lies in the modification of the list while you are iterating over it. If you want to modify, you are not allowed to change the list while you iterate over it.

Save the instances you want to remove, and then remove them after (Pseudocode):

ArrayList<Item> ItemsToRemove = new ArrayList<Item>();

for(Item item : allItems){
  if(shouldItemBeRemoved(item)){
    ItemsToRemove.add(item)
  }
}

//Remove the items for the allItems list
for(Item item : itemToRemove){
  allItems.remove(item);
}

or remove the items using the iterator:

iterMissiles.remove();
Rawa
  • 13,357
  • 6
  • 39
  • 55
0

One may not alter the list one is iterating over:

enemiesKilled.add(enemiesLeft.remove(enemiesLeft.indexOf(e)));

should be:

iterEnimies.remove();
enemiesKilled.add(e);
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

Problem is here:

 while(iterMissiles.hasNext()){
      Missile m = iterMissiles.next();  //current Missile
      if(e.doesIntersect(m)){           
      //remove Enemy from enemiesLeft and add it to enemiesKilled list
      enemiesKilled.add(enemiesLeft.remove(enemiesLeft.indexOf(e)));
      //remove Missile
      missiles.remove(m);
      }

You try to remove item from missiles when iterate over it. It's throws java.util.ConcurrentModificationException

Add new list before iterating over missiles:

LinkedList<Missile> missilesForRemove = new LinkedList<Missile>();

and add to this list m variable and after while loop remove this missilesForRemove from your original missiles list:

missiles.removeAll(missilesForRemove);
Aleksandr Podkutin
  • 2,532
  • 1
  • 20
  • 31