Removing objects from arrays while iterating Java

I am trying to remove both the ship and the projectile when they collide. To do this, I repeat two advanced for-loops and I try to remove them when they overlap. Unfortunately, edditing for-loops when iterating through them is not a good idea and it throws a ConcurrentModificationException, so I disabled them for the Iterators, which seems to work.

public void collision()
{
    Iterator<Ship> itShips = Ship.ships.iterator();
    Iterator<Projectile> itProj = Projectile.projectiles.iterator();

    while (itShips.hasNext()) {
        Ship ship = itShips.next();

        while (itProj.hasNext()) {
            Projectile proj = itProj.next();

            if (ship.c != proj.c) {
                Rectangle.Float r1 = ship.getBounds();
                Rectangle.Float r2 = proj.getBounds();

                if (r1.intersects(r2)) {
                    itProj.remove();
                    itShips.remove();
                    break;
                }
            }
        }
    }
}

      

the problem is that the ConcurrentModificationException property seems to have moved to where I am calling my updates. I also tried replacing these for-loops with iterators, but it doesn't seem to work and throws the same exception, but now in the update () method.

public void update()
{   
    Iterator<Ship> it1 = Ship.ships.iterator();
    while (it1.hasNext()) {
        Ship s = it1.next();
        s.update(game);
    }

    Iterator<Projectile> it2 = Projectile.projectiles.iterator();
    while (it2.hasNext()) {
        Projectile p = it2.next();
        p.update(game);
    }
}

      

Should I change how I update my game objects or how I save them? Or am I doing object deletion wrong?

+3


source to share


4 answers


Since it still gave an error in my update () method, I saved the collidedObjects in arrays. Using these arrays, I can remove them from the original Ship and Projectile arrays. I do this by calling another method in the update () method that compares and deletes objects.



public void collision()
{
    Ship shipToRemove = null;
    Projectile projToRemove = null;

    outerLoop:
    for (Ship ship : Ship.ships) {
        for (Projectile proj : Projectile.projectiles) {
            if (ship.c != proj.c) {

                Rectangle.Float r1 = ship.getBounds();
                Rectangle.Float r2 = proj.getBounds();

                if (r1.intersects(r2)) {
                    shipToRemove = ship;
                    projToRemove = proj;
                    playSound();
                    break outerLoop;
                }
            }
        }
    }
    projALToRemove.add(projToRemove);
    shipALToRemove.add(shipToRemove);
}

public void update()
{

    for (Ship ship : Ship.ships) {
        ship.update(game);
    }
    for (Projectile proj : Projectile.projectiles) {
        proj.update(game);
    }
    deleteAfterCollision();
}

public void deleteAfterCollision()
{
    for (Ship ship : Ship.shipALToRemove) {
        Ship.ships.remove(ship);
    }
    for (Projectile proj : Ship.projALToRemove) {
        Projectile.projectiles.remove(proj);
    }
}

      

0


source


You can keep those that collide with some variable, after you end the loop, remove those from the lists:

Ship shipToRemove = null;
Projectile projToRemove = null;

Iterator<Ship> itShips = Ship.ships.iterator();
Iterator<Projectile> itProj = Projectile.projectiles.iterator();

while (itShips.hasNext()) {
    Ship ship = itShips.next();

    while (itProj.hasNext()) {
        Projectile proj = itProj.next();


        if (ship.c != proj.c) {
            Rectangle.Float r1 = ship.getBounds();
            Rectangle.Float r2 = proj.getBounds();

            if (r1.intersects(r2)) {
                shipToRemove = ship;
                projToRemove = proj;
                break;
            }
        }
    }
}

Projectile.projectiles.remove(projToRemove);
Ship.ships.remove(shipToRemove);

      



What should do it.

+2


source


The iterator does not support adding while iterating. The collection iterator uses expectModCount to check if it has changed by others. When you add using a given value, the modCount value is incremented and it is expected that the ModCount value has not changed, throw an exception.

You should track and perform the update operation for the last time.

if (modCount != expectedModCount)
                throw new ConcurrentModificationException();




 public interface Iterator {

    boolean hasNext();

    E next();

    void remove();
    }

      

0


source


A functional way of approaching the problem is filter

non-colliding ships and shells. This approach avoids problems arising from the simultaneous modification of several objects. I am assuming that Ship.ships

both Projectile.projectiles

are objects List

and will work with them instead of their iterators:

List<Ship> ships = Ship.ships;
List<Projectile> projs = Projectile.projectiles;

Stream<Rectangle.Float> shipBounds = ships.stream().map(s -> s.getBounds());
Stream<Rectangle.Float> projBounds = projs.stream().map(p -> p.getBounds());

List<Ship> safeShips = ships
        .stream()
        .filter(s -> !projBounds.anyMatch(p -> p.intersects(s.getBounds())))
        .collect(Collectors.toList());

List<Projectile> safeProjs = projs
        .stream()
        .filter(p -> !shipBounds.anyMatch(s -> s.intersects(p.getBounds())))
        .collect(Collectors.toList());

      

0


source







All Articles