I'm working on a Missile Command remake in libgdx.
I have 3 array lists: bullets, missiles, and houses.
I've been trying to iterate through the lists to detect collisions between missiles and houses, and missiles and bullets, but I get this very broad error message for everything I've tried so far:
Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:372)
at java.base/java.util.ArrayList.get(ArrayList.java:458)
at com.mygdx.game.Screen.MCGameScreen.render(MCGameScreen.java:112)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
Theres been the same issue with every way I've tried to iterate through the lists that causes the (probably missiles) array list to check for something at a position that was already removed due to a collision. I do not want to "reuse" the objects in the array, and I'd much prefer just removing them.
This is the code for creating a new missile, and adding them to the missiles array, every 2 seconds a new missile is created, given a random position along the top of the screen, and added to missiles.
timer += delta;
if(timer >= 2) {
Sprite temp = new Sprite(missile);
temp.setPosition((float) (Math.random() * Gdx.graphics.getWidth() - temp.getWidth()), Gdx.graphics.getHeight());
missiles.add(temp);
timer = 0;
}
This is the code for creating a new bullet, and adding it to the bullets array, every time the space bar is pressed, a new bullet is created, set to the center of the tank's position, and added to bullets.
if(keycode == Input.Keys.SPACE) {
Sprite temp = new Sprite(bullet);
temp.setPosition(tank.getX() + tank.getWidth()/2 - temp.getWidth()/2, tank.getY() + tank.getHeight());
bullets.add(temp);
}
This is the initialization of the preset sprites I use when creating the temp variables to be added to the lists, as well as the arraylists themselves.
bullet = new Sprite(new Texture("bullet.png"));
bullets = new ArrayList<>();
missile = new Sprite(new Texture("missile.png"));
missiles = new ArrayList<>();
house = new Sprite(new Texture("house.png"));
houses = new ArrayList<>();
This is the first way I've tried to check for collisions where I also used the same loops to move the missiles and bullets.
for(int i = bullets.size()-1; i >= 0; i--) {
bullets.get(i).translateY(bulletSpeed);
if(bullets.get(i).getY() >= Gdx.graphics.getHeight() + bullet.getHeight()) {
bullets.remove(i);
}
for(int j = missiles.size()-1; j >= 0; j--) {
if(missiles.get(j).getBoundingRectangle().overlaps(bullets.get(i).getBoundingRectangle())) {
missiles.remove(j);
bullets.remove(i);
}
}
}
for(int i = missiles.size()-1; i >= 0; i--) {
missiles.get(i).translateY(missileSpeed);
if(missiles.get(i).getY() <= 0) {
missiles.remove(i);
}
for(int j = houses.size()-1; j >= 0; j--) {
if(houses.get(j).getBoundingRectangle().overlaps(missiles.get(i).getBoundingRectangle())) {
houses.remove(j);
missiles.remove(i);
}
}
}
This is the second method I've tried, I split up everything in to separate loops in case the index of the array was still being used in the loop even after it was removed.
for(int i = bullets.size()-1; i >= 0; i--) {
bullets.get(i).translateY(bulletSpeed);
if(bullets.get(i).getY() >= Gdx.graphics.getHeight() + bullet.getHeight()) {
bullets.remove(i);
}
}
for(int i = missiles.size()-1; i >= 0; i--) {
missiles.get(i).translateY(missileSpeed);
if(missiles.get(i).getY() <= 0) {
missiles.remove(i);
}
}
for(int i = missiles.size()-1; i >= 0; i--) {
for(int j = bullets.size()-1; j >= 0; j--) {
if(missiles.get(i).getBoundingRectangle().overlaps(bullets.get(j).getBoundingRectangle())) {
missiles.remove(i);
bullets.remove(j);
}
}
}
for(int i = missiles.size()-1; i >= 0; i--) {
for(int j = houses.size()-1; j >= 0; j--) {
if(missiles.get(i).getBoundingRectangle().overlaps(houses.get(j).getBoundingRectangle())) {
missiles.remove(i);
houses.remove(j);
}
}
}
I've also tried this variant, using enhanced for loops.
for(Sprite missile: missiles) {
missile.translateY(missileSpeed);
if(missile.getY() <= 0) {
missiles.remove(missiles.indexOf(missile));
}
}
for(Sprite bullet: bullets) {
bullet.translateY(bulletSpeed);
if(bullet.getY() >= Gdx.graphics.getHeight() + bullet.getHeight()) {
bullets.remove(bullets.indexOf(bullet));
}
}
for(Sprite missile: missiles) {
for(Sprite bullet: bullets) {
if(missile.getBoundingRectangle().overlaps(bullet.getBoundingRectangle())) {
missiles.remove(missiles.indexOf(missile));
bullets.remove(bullets.indexOf(bullet));
}
}
}
Please let me know if you need any details that I left out!