Search code examples
javalibgdxcollision-detection

I'm getting an ArrayIndexOutOfBounds Exception and I don't know why. Can someone shed some light?


This is my first time making a 2D game. The code is in Java.

I have a character that can shoot blasts at zombies, and this is how I have been dealing with the collision detection between the blasts and zombies.

I am getting an ArrayIndexOutOfBounds Exception for the line: blastIter.remove();

Why is that?

Iterator<Rectangle> blastIter = blasts.iterator();
Iterator<Zombie> zombieIter;

while(blastIter.hasNext()) {
    Rectangle blast = blastIter.next();
    blast.x += 200 * Gdx.graphics.getDeltaTime();
    if(blast.x > window.length) blastIter.remove();

    zombieIter = zombies.iterator();
    while(zombieIter.hasNext()) {
        Zombie zombie = zombieIter.next();
        if(zombie.overlaps(blast)) {
            zombie.removeHealth(5);
            blastIter.remove();
            if (zombie.isDead()) {
                zombiesSlain++;
                zombieIter.remove();
            }
        }
    }
}

As requested, here is the complete stack trace:

Exception in thread "LWJGL Application" java.lang.ArrayIndexOutOfBoundsException: -1 at com.badlogic.gdx.utils.Array.removeIndex(Array.java:231) at com.badlogic.gdx.utils.Array$ArrayIterator.remove(Array.java:540) at com.test.drop.Drop.render(Drop.java:128) at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:208) at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)


Solution

  • Having blastIter.remove(); in the inner loop is problematic, since you might try to remove the same blast multiple times. In addition, you might remove the blast before ever getting to the inner loop, in which case the inner loop should be skipped.

    I'd suggest adding a flag that would prevent a blast from being removed more than once :

    while(blastIter.hasNext()) {
        Rectangle blast = blastIter.next();
        blast.x += 200 * Gdx.graphics.getDeltaTime();
        boolean removed = false;
        if(blast.x + 16 > window.length) {
            blastIter.remove();
            removed = true;
        }
        zombieIter = zombies.iterator();
        while(zombieIter.hasNext() && !removed) {
            Zombie zombie = zombieIter.next();
            if(zombie.overlaps(blast)) {
                removed = true;
                zombie.removeHealth(5);
                blastIter.remove();
                if (zombie.isDead()) {
                    zombiesSlain++;
                    zombieIter.remove();
                }
            }
        }
    }