I know this has probably been asked many times before, but I have a problem and I could not find a solution that particularly targeted my issue.
The problem is as follows:
I have two arraylists of rockets and projectiles, and collision is checked between them. When they collide, both of them are removed. The problem is that when the only rocket in the arraylist is hit, the exception occurs, and I have no idea how to stop it from happening.
java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at adam.miszczak.defendthebase.level.Level.collision(Level.java:158)
at adam.miszczak.defendthebase.level.Level.tick(Level.java:144)
at adam.miszczak.defendthebase.Game.tick(Game.java:124)
at adam.miszczak.defendthebase.Game.run(Game.java:104)
at java.lang.Thread.run(Unknown Source)
Collision method + the arraylists:
public static ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
private static ArrayList<Rocket> rockets = new ArrayList<Rocket>();
private void collision(){
for(int i = 0; i < rockets.size(); i++){
for(int j = 0; j < projectiles.size(); j++){
try{
if(rockets.get(i).bounds().intersects(projectiles.get(j).bounds())){
projectiles.remove(j);
rockets.get(i).die();
stats.addScore(rockets.get(i));
Particle p = new Particle(20, 20, 20, 50);
particles.add(p);
}
}catch(IndexOutOfBoundsException e){
e.printStackTrace();
}
}
}
}
Remove and Add methods:
private void remove(ArrayList<Projectile> projectiles, ArrayList<Rocket> rockets){
for(int i = 0; i < rockets.size(); i++){
if(rockets.get(i).getVisible()){ rockets.remove(i); rocketsOnScreen--; }
}
for(int i = 0; i < projectiles.size(); i++){
if(projectiles.get(i).isRemoved()){ projectiles.remove(i);}
}
for(int i = 0; i < planes.size(); i++){
if(planes.get(i).isRemoved()){ planes.remove(i); planesOnLevel--;}
}
}
private void spawnRocket(int rocketType, int x, ArrayList<Rocket> rockets) {
switch (rocketType) {
case ROCKET_NORMAL:
rockets.add(new NormalRocket(x, -10, 80, 0, 2));
rocketsSpawned++;
rocketsOnScreen++;
break;
case ROCKET_FIRE:
if(difficulty > 1 && random.nextInt(100) > fireRocketSpawn){
rockets.add(new FireRocket(x, -10, 70, 0, 2));
rocketsSpawned++;
rocketsOnScreen++;
}else{
return;
}
break;
case ROCKET_ZIPPER:
if(difficulty > 2 && random.nextInt(100) > zipperRocketSpawn){
rockets.add(new ZipperRocket(x, -10, 40, 0, 4));
rocketsSpawned++;
rocketsOnScreen++;
}else{
return;
}
break;
case ROCKET_TANK:
if(difficulty > 3 && random.nextInt(100) > tankRocketSpawn){
rockets.add(new TankRocket(x, -10, 130, 0, 1));
rocketsSpawned++;
rocketsOnScreen++;
}else{
return;
}
break;
}
}
NOTE: rocket.die() basically just removes the rocket, the same way the remove method would do.
You cannot remove while iterating over a List
with anything other than an Iterator
. Imagine the consequences; you are looping over the elements and remove element n
. All other elements shift down one to fill the gap. You take element n+1
, this is now element n+2
from when you started looping. And the List
is one element smaller so your bounds check is now wrong. You can get all sorts of hard to track-down bugs in this manner.
In Java if you use the proper syntax - ie enhanced foreach loops then your will get the correct error if you even try to addto/deletefrom the list while iterating - you will get a ConcurrentModificationException
.
To fix your method, 1) get rid of all the indices. You are abusing them and they are unnecessary (now many times do you get the same element from each List
in each iteration?) . 2) use an actual Iterator
for the inner loop so that you can call Iterator.remove
to remove the last returned element from the List
. Because that is done via the Iterator
it doesn't result in an error:
private void collision() {
for (final Rocket rocket : rockets) {
final Iterator<Projectile> iter = projectiles.iterator();
while (iter.hasNext()) {
final Projectile projectile = iter.next();
if (rocket.bounds().intersects(projectile.bounds())) {
rocket.die();
stats.addScore(rocket);
Particle p = new Particle(20, 20, 20, 50);
particles.add(p);
iter.remove();
}
}
}
}
Never remove items of a list during a loop through the list. It might give concurrency oroblems. Mark the numbers for removal right after the loop.
Not sure if it will fix your problem, but sure enough you should fix that too.
When the collision is detected you call
rockets.get(i).die();
'die' removes the rocket from the 'Arraylist', you say. Then you call
stats.addScore(rockets.get(i));
which will crash (this line is 158, isn't it? )
Apologies for brevity and formatting, first answer from my phone :-)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.