for IndexOutOfBoundsException:
Hi i'm making a space invader like game and i have a problem when a bullet collides with the enemy. Here is the code:
for (int i = 0; i < enemies.size(); i++) {
for (int j = 0; j < bullets.size(); j++) {
if (collidesWith(bullets.get(j), enemies.get(i))) { //Line 81 The Error Occurred here
enemies.remove(i);
bullets.remove(j);
addScore(1);
}
}
}
Code for the Colliding:
public static boolean collidesWith(Entity collider, Entity collided) {
Rectangle hitBox1 = collider.getHitbox();
Rectangle hitBox2 = collided.getHitbox();
return hitBox1.intersects(hitBox2);
}
Code for the Hitbox:
@Override
public Rectangle getHitbox() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
The Error Messages:
Exception in thread "Thread-4" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.get(ArrayList.java:411)
at io.github.kjordo711.game.Main.run(Main.java:81)
at java.lang.Thread.run(Thread.java:724)
I think the error cause by 2 or more bullets hits the enemy
for OutOfMemoryError:
The Player can shoot too many bullets at once if they hold Space the bullet will keep shooting without delaying i could limit the bullet spawning but the problem is even with 10 bullets max on screen the error still occur, i tried to delay it with
Thread.sleep(500);
but it just sleep all the game thread
3 Answers 3
It's because you're removing object within the loops, which is not correct and besides ArrayIndexOutOfBoundsException this can cause a ConcurrentModificationExcetion, also.
When you're supposed to remove an object from a collection, consider using the java.util.Iterator interface.
Iterator<Enemy> enemiesIterator = enemies.iterator();
Iterator<Entity> bulletsIterator = bullets.iterator();
while (enemiesIterator.hasNext()) {
Enemy nextEnemy = enemiesIterator.next();
while(bulletsIterator.hasNext()) {
Entity nextBullet = bulletsIterator.next();
if (colliesWith(nextBullet, nextEnemy) {
enemierIterator.remove();
bulletsIterator.remove();
addScore(1);
}
}
}
2 Comments
Entity from the signature of the collidesWith() method. Anyway, I'm glad it works. Note that I'm not aware of what object are you collections parametrized with. :)The problem is that you remove objects inside your nested loops. Once you remove an enemy at i, the list of enemies becomes shorter by one. If i happens to be equal to the old length of enemies, subsequent calls to enemies.get(i) are going to cause an exception. Since the inner loop does not re-check i, this situation is possible. Adding a guard for that and iterating backwards (something that you do when items could be removed as you go) should take care of the exception and avoid skipping collision checks on removals:
for (int i = enemies.size()-1 ; i >= 0 ; i--) {
for (int j = bullets.size()-1 ; j >= 0 && i < enemies.size() ; j--) {
if (collidesWith(bullets.get(j), enemies.get(i))) {
enemies.remove(i);
bullets.remove(j);
addScore(1);
}
}
}
3 Comments
I'll answer your concern about your second problem: using Thread.sleep(...) will block the current Thread, which probably is the EDT, freezing your whole game. If you want to avoid firing too many bullets, you should use System.currentTimeMillis() for each Space keystroke and compare it to the last one that actually fired a bullet:
static final int RECOIL = 500; // Minimum ms to wait between two shots
long lastShotMs = 0;
void fireBullet() { // Called when spacebar is pressed
long shotMs = System.currentTimeMillis();
if (shotMs - lastShotMs < RECOIL)
return;
lastShotMs = shotMs;
doFireBullet(); // Perform the bullet-firing
}