Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Im getting:

    09-02 17:15:39.140: E/AndroidRuntime(533): java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1
    09-02 17:15:39.140: E/AndroidRuntime(533):  at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)

when Im killing enemies using this method:

    private void checkCollision() {
    Rect h1 = happy.getBounds();
    for (int i = 0; i < enemies.size(); i++) {
        for (int j = 0; j < bullets.size(); j++) {
            Rect b1 = bullets.get(j).getBounds();
            Rect e1 = enemies.get(i).getBounds();
            if (b1.intersect(e1)) {
                enemies.get(i).damageHP(5);
                bullets.remove(j);
                Log.d("TAG", "HERE: LOLTHEYTOUCHED");
            }
            if (h1.intersect(e1)){
                happy.damageHP(5);
            }
            if(enemies.get(i).getHP() <= 0){
                enemies.remove(i);
            }
            if(happy.getHP() <= 0){
                //end-screen                           !!!!!!!
            }
        }
    }
}

using this ArrayList:

        private ArrayList<Enemy> enemies = new ArrayList<Enemy>();

and adding to array like this:

   public void createEnemies() {
    Bitmap bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.female);
    if (enemyCounter < 24) {
        enemies.add(new Enemy(bmp, this, controls));
    }
    enemyCounter++;
}

I dont really understand what the problem is, Ive been looking around for a while but cant really find anything that helps me. If you know or if you can link me someplace where they have a solution for a similar problem Ill be a very happy camper!

Thanks for ur time.

share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

The problem is the removal of elements from the enemies list. If the condition enemies.get(i).getHP() <= 0 becomes true for an enemy object it may remove more than the intended object since your inner loop will continue to run. The fix is to break out of the inner loop and start checking the next enemy object:

if(enemies.get(i).getHP() <= 0){
    enemies.remove(i);
    break;
}
share|improve this answer
    
Helped me. Thanks. –  Justin Skiles Sep 2 '12 at 18:45
    
This will fix the exception, however remove shifts all remaining enemies one index towards zero, so after you break out of the loop the next enemy will be skipped. –  Eric Sep 2 '12 at 18:49
    
looks like this fixed it, simple and efficient. Thank you good sir! –  iQue Sep 2 '12 at 19:38
add comment

This happens when an "earlier" bullet has killed one or more of your enemies, and they are removed with enemies.remove(i); in such a way that now i >= enemies.size() (e.g. when it was the last enemy or enemies in the ArrayList). A "later" bullet will now be checked against an enemy index that no longer exists, and enemies.get(i) throws an IndexOutOfBoundsException.

It is generally a bad idea to thoughtlessly iterate over and remove from the same collection: you'll never know where your references end up (in this case i doesn't point anymore where you think it does). One way around this is to have a separate clean-up loop when you know your "dead" objects can no longer be referenced. To know which objects to clean-up, either:

  • Use a property (toBeDeleted) for the objects that need to be removed, or
  • Keep track of the set of indices that have been deprecated

So:

for (Enemy enemy : enemies) {

    // Check collisions with bullets.
    for (Bullet bullet : bullets) {
        if ( bullet.collides(enemy) ) {
            enemy.hit();
            bullet.setDelete(true);
        }
    }

    // Clean-up bullets.
    for (Iterator<Bullet> it = bullets.iterator(); it.hasNext(); )
        if ( it.next().isDelete() )
             it.remove();

    // Enemy-Happy collision bonus optimization.
    if ( happy.collides(enemy) ){
        happy.hit();
    }

    // Flag dead enemies.
    if ( enemy.hp() <= 0 ) {
        enemy.setDelete(true);
    }
}

// Clean-up enemies.
for (Iterator<Enemy> it = enemies.iterator(); it.hasNext(); )
    if ( it.next().isDelete() )
        it.remove();
share|improve this answer
    
Another option is running through your collections backwards (for (int i = enemies.size()-1; i >= 0; i--))... –  Eric Sep 2 '12 at 18:53
    
Hi Eric, wouldn't this suffer from the "skip" after the remove? For example, if you are at index 0 and remove the enemy there, the iterator continues after collection is shifted. –  Justin Skiles Sep 3 '12 at 5:15
    
(Assuming you're referring to the comment.) I have to add you still need to add @johlo's break to prevent the exception (which I think you already noticed). It won't result in a skip, because we are moving leftwards through the collection and only elements to the right will be shifted. So those elements will have the wrong i-value pointing at them, but we've already processed them earlier in this iteration and it is not a problem. –  Eric Sep 3 '12 at 10:00
    
Hi Eric. Sorry, I meant your answer, since you are moving forward (left to right) in the collection. If we delete at index 0, then move to index 1, the item that was at 1 is now at 0 and has been skipped. –  Justin Skiles Sep 3 '12 at 15:08
    
In the first nested loops I'm not deleting while iterating, just flagging objects for deletion. Later on I use Iterator.remove() in a loop, but it is safe to do so. See also: Efficient equivalent for removing elements while iterating the Collection. –  Eric Sep 3 '12 at 19:41
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.