collision - how to avoid indexOutOfBoundsException?

edited November 2016 in Questions about Code

Hello processing forum!

I have made a game where you fly around with a spaceship, you need to avoid incoming meteors or shoot them. But sometimes, when two meteors are on top of eachother, and you shoot them i get an OutOfBounds error, when they are deleted from the ArrayList.

error OutOfBounds

This is the collision detection method:

  void bulletCollideMeteor() {
    for (int i = particles.size()-1; i >= 0; i--) {
      Bullet bullet = particles.get(i);
      for (int j = meteors.size()-1; j >= 0; j--) {
        Meteor meteor = meteors.get(j);

        float d = dist(bullet.x, bullet.y, meteor.x, meteor.y);

        if (d < bulletR + meteorR) {
          bulletHitMeteor = true;
        } else {
          bulletHitMeteor = false;
        }

        if (bulletHitMeteor) {
          particles.remove(i);
          meteors.remove(j);
          score += 10;
          explosion.rewind();
          explosion.play();
        }
      }
    }
  }

The meteors spawn at random pre-determined locations at y = -200 and then get a random speed.

  void meteor() {
    int rLoc = int(random(0, 6));
    float xdir =int(random(-4, 4));
    float ydir =int(random(8, 16));
    meteors.add(new Meteor(vectors[rLoc].x, vectors[rLoc].y, xdir, ydir));

can you think of any way to solve this problem?

I have thought of having the meteors x-speed mulitplied by -1 to change their direction. But this fails when i cant acess their x-values separately.

thanks in advance!

Answers

  • In order to safely remove items from a list, loop through that list backwards rather than forwards in the loop that contains the remove call.

  • eeehm am i not doing this?

    for (int i = particles.size()-1; i >= 0; i--) {
        Bullet bullet = particles.get(i);
        for (int j = meteors.size()-1; j >= 0; j--) {
          Meteor meteor = meteors.get(j);
    
  • What is happening is that you removed the ith element twice for the same i. How about this, why not let a single bullet hit only one meteor? In that case, new code:

    void bulletCollideMeteor() {
      for (int i = particles.size()-1; i >= 0; i--) {
        Bullet bullet = particles.get(i);
        for (int j = meteors.size()-1; j >= 0; j--) {
          Meteor meteor = meteors.get(j);
    
          float d = dist(bullet.x, bullet.y, meteor.x, meteor.y);
    
          if (d < bulletR + meteorR) {
            bulletHitMeteor = true;
          } else {
            bulletHitMeteor = false;
          }
    
          if (bulletHitMeteor) {
            particles.remove(i);
            meteors.remove(j);
            score += 10;
            explosion.rewind();
            explosion.play();
            break;
          }
        }
      }
    }  
    

    Otherwise, you could do this:

    void bulletCollideMeteor() {
      for (int i = particles.size()-1; i >= 0; i--) {
        Bullet bullet = particles.get(i);
        boolean used = false;
        for (int j = meteors.size()-1; j >= 0; j--) {
          Meteor meteor = meteors.get(j);
    
          float d = dist(bullet.x, bullet.y, meteor.x, meteor.y);
    
          if (d < bulletR + meteorR) {
            bulletHitMeteor = true;
          } else {
            bulletHitMeteor = false;
          }
    
          if (bulletHitMeteor) {
            used = true;
            meteors.remove(j);
            score += 10;
            explosion.rewind();
            explosion.play();
          }
        }
        if(used)particles.remove(i);
      }
    }  
    
  • Very clever! :) thanks man!

  • A third option to fix this kind of problem:

    If a set of loops have the possibility of removing the same item multiple times (thus causing an error, since you are deleting an already-deleted thing), and you don't want to refactor, you can sometimes break after removing an item, jumping out of the loops. This will skip all other checks for that iteration, of course....

  • @jeremydouglass Isn't my first answer the same as what you say?

  • @Lord_of_the_Galaxy -- oh, you are right! They are the same. I hadn't noticed the break in your first example.

Sign In or Register to comment.