Removing Projectiles

I’m making a game kind of like Super Smash Bros. One of the attacks available to the player is a projectile fireball. All the fireball animation and collision is working perfectly, but whenever the code goes to remove a projectile from the screen, I get the following exception:


Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
        at java.util.AbstractList$Itr.next(AbstractList.java:343)
        at Main.run(Main.java:213)
        at Main.<init>(Main.java:67)
        at Main.main(Main.java:307)

I’m using the following code for looping and removing:

 
//looping, this is inside the class that draws everything
for(Attack a: projectiles)
{
      a.update(bg);
}
//removing this is inside the projectile class
public void removeFromWorld()
{
    Main.projectiles.remove(this);
}

Currently I’m using an ArrayList to hold all the projectile data. Would it help if I used a different type of array or made a flag in the projectile class that indicated that the projectile should no longer be updated/drawn?

Thanks for the help!

In your base entity class, keep a boolean named expired. This will be set to false in the beginning. When the entity needs to be removed, set expired to true. In your update method or whatever, check if expired is true, and if it is, remove that entity.

The concurrent modification exception still happens. :-\

Where is the remove being called, and how are you detecting when to remove which projectile?

Originally the remove was being called from inside the projectiles instance, but then I changed it using the flag method suggest by Agro. That didn’t work either. The two instances in which the projectile is removed from the screen is when it leaves the viewing screen and when it hits the player or the AI (depending on who originally shot it). The collision detection is in the loop that I showed in the original post. I’m using

projectiles.remove(a);

to remove the projectile.

Use the “if-alive-copy-into-new-list” approach.

Pseudo-Code:


List newList = new List;

for(Entity e : currentList){
    e.logic();
    
    if(e.isAlive())
        newList.add(e);
}

currentList = newList;

  • Longor1996

That causes the game to crash the when the projectile is added rather than when it is removed. :confused:

Edit: I switched using straight up Arrays and Longor’s method and now it works! Using an Array also drastically increased performance, now my tick timer is all messed up. Thanks to everyone who helped!

It should probably look something like this.


for(int i = 0;i < projectiles.size();i++){
     Attack a = projectiles.get(i);
     if(a.exists){
          a.update(bg);
     } else {
          projectiles.remove(i);
     }
}

This is where Iterators still come in handy, as they are designed to allow removal of an element during traversal.


for (Iterator<Attack> i = projectiles.iterator(); i.hasNext();) {
    Attack a = i.next();
    if (a.exists() {
        a.update(bg);
    } else {
        i.remove(); // this will remove the current element from the iterator
    }
}

The code isn’t as nice but they do the job.

Iterator is one solution; although some might argue it creates garbage within a frame loop. Probably negligible, but here are some other solutions for removing items from a list while iterating through it:

for (int i=0; i<list.size(); i++) {
    list.get(i).update();
    if (!list.get(i).isActive()) { //entity is dead, remove
        list.remove(i);
        i--; //move back one
    }
}

The problem with the above is that it leads to a lot of shifting and arraycopies (moves all subsequent elements to the left by one) which can be slow. In reality the performance loss is negligible for most games, but here is another solution that doesn’t lead to so much shifting:

for (int i=list.size()-1; i>=0; i--) {
    list.get(i).update();
    if (!list.get(i).isActive()) { //entity is dead, remove
        list.remove(i);
    }
}

The above introduces another problem; that you are iterating through in the reverse order. For many games this can be an issue, since generally you expect entities to be updated in the order they were created in.

A very clean and efficient solution is to actually to use a double-buffering technique, described here by Cas: