3

I'm trying to delete both a ship and a projectile when they collide. To do this I'm iterating through two advanced for-loops and I try to delete them when they intersect. Unfortunately edditing for-loops while iterating through them isn't a good idea and it throws an ConcurrentModificationException, so I switched them out for Iterators, which seems to be working.

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 seems to have moved to where I call my updaters. I tried swapping those for-loops out for iterators as well, 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 the way I update my gameobjects or the way I save them? Or am I doing the deletion of the objects the wrong way?

4 Answers 4

2

You can save those that collide to some variable, then after you finish looping, 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);

Which should do it.

Sign up to request clarification or add additional context in comments.

3 Comments

This still gives me an error in my update method. I might however be able to use this to delete them after I itterated this way.
@Muxor If you find an answer useful, you should upvote it, so that future readers know it's useful.
For people with the same problem: I used this idea, but because it still gave me an error in the update() method I had to change it a bit. Instead of directly removing the collideObjects, I stored them in an array. In my update method I put some code to delete the stored collidedObjects from the array the actual objects are stored in.
0

Iterator does not support add while iterating .In collection iterator use expectedModCount to check if it is modified by other.When you do some add using set reference modCount value increases and expectedModCount not changed cause exception.

You should track and do the update operation in last.

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




 public interface Iterator {

    boolean hasNext();

    E next();

    void remove();
    }

Comments

0

Since it still gave an error in my update() method, I stored the collidedObjects in arrays. Using these arrays I can delete them from the original Ship and Projectile arrays. I do this by calling another method in the update() method which compares and deletes the 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);
    }
}

Comments

0

A functional way to approach the problem is to filter the non-colliding ships and projectiles. This approach avoids the problems that arise from concurrently mutating multiple objects. I assume that Ship.ships and Projectile.projectiles are List objects and will work with those 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());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.