Индекс массива вне границ - PullRequest
0 голосов
/ 30 ноября 2011

Я не знаю, что мне не хватает ... полный код довольно большой, поэтому я просто выложу часть, выдающую исключения здесь.

      for (int i = 0; i < player.getBullets().size(); i++) { //for every player bullet
            for (int j = 0; j < aliens.getAliens().size(); j++) { //for every player bullet every alien
                player.getBullets().get(i);
                aliens.getAliens().get(j);
                if (player.getBullets().get(i).getBounds().intersects(aliens.getAliens().get(j).getBounds())){ //player bullet vs alien collison
                    if (aliens.getAliens().get(j).getType() == 1)
                        score += 2 + level;
                    else if(aliens.getAliens().get(j).getType() == 2)
                        score += 4 + level;
                    else
                        score += 8 + level*2;
                    aliens.getAliens().remove(j); // alien dies
                    player.getBullets().remove(i);
                    System.out.println("player bullet removed");
                }
            }
        }       

Она вызвала исключение в // игрок пуля против линии столкновения с инопланетянами.Я добавил в player.getBullets().get(i) и getAliens(), чтобы определить, какое из них вызвало исключение, и это было игроком.

Ошибка кажется случайной, но я считаю она выходитграничит, когда инопланетянин движется вбок на пулю.Это работает хорошо, если пуля попадает в инопланетянина прямо на.Может ли это быть ошибкой при использовании пересечений?

Кстати, это мимика Space Invaders.Любая помощь будет оценена.

Ответы [ 7 ]

3 голосов
/ 30 ноября 2011

Используйте Iterator, который поддерживает операцию remove в своей коллекции. Чтобы дать вам представление (весь ненужный код из OP удален):

    List<Bullet> bullets = new ArrayList<Bullet>();
    List<Alien> aliens = new ArrayList<Alien>();

    Iterator<Alien> alienIterator = aliens.iterator();
    Iterator<Bullet> bulletIterator = bullets.iterator();
    while (bulletIterator.hasNext()) { //for every player bullet
        while (alienIterator.hasNext()) { //for every player bullet every alien
            Bullet bullet = bulletIterator.next();
            Alien alien = alienIterator.next();
            if (bullet.getBounds().intersects(alien.getBounds())) { //player bullet vs alien collison
                bulletIterator.remove();
                alienIterator.remove();
                System.out.println("player bullet removed");
            }
        }
    }

Обратите внимание, что он все еще восприимчив к IllegalStateException, если вы изменяете инопланетян / пули в другом месте одновременно.

2 голосов
/ 30 ноября 2011

Вы изменяете свои списки по мере их обхода (вызывая .remove() внутри цикла). Вы удаляете пулю во время проверки на столкновение с ней.

Одно из решений - дать инопланетянам / пулям / другим подобным объектам переменную isDead. Затем, вместо того, чтобы удалять их внутри цикла, подождите до окончания цикла и удалите всех с помощью isDead == true.

1 голос
/ 30 ноября 2011

Допустим, игрок 0 убит. Когда вы удаляете его пулю, все остальные пули перемещаются вниз на одну в индексе. Поэтому, когда индекс увеличивается до 1, вы будете смотреть на то, что изначально было маркером 2, а не маркером 1.

При удалении из списка по индексу, всегда проходят через циклы в обратном порядке, чтобы не влиять на порядок элементов, которые еще нужно просмотреть.

Однако проблема, которую вы видите (капо), возникает, если последняя пуля что-то убивает. Пока вы находитесь в цикле for (j), вы удаляете последнюю пулю. Следующий вызов getBullet (i) потерпит неудачу, потому что больше нет маркера i, теперь есть только i-1. Когда пуля что-то убивает, вы должны вырваться из внутренней петли. (Предполагая, что пуля не может убить 2 пришельцев одновременно)

Тем не менее, вы будете гораздо лучше обслуживаться

  1. Используя новый стиль зацикливания, for (Bullet bullet : player.getBullets() {} Это действительно действительно упростит ваш код !!!
  2. Подумайте не удалять на лету. Соберите все, что нужно удалить, в два временных списка: deadAliens и usedBullets. В конце вашего цикла вызов

    aliens.getAliens (). RemoveAll (deadAliens); player.getBullets () RemoveAll (deadBullets);.

1 голос
/ 30 ноября 2011

Вы должны создать итераторы для перебора игроков и инопланетян.Затем, когда его нужно удалить, сделайте это на итераторе вместо исходного списка.Это делает зацикливание работающим.

Как @Toomai предлагает вместо удаления пометить их как мертвые, возможно, удалить их позже, также хорошее решение.

1 голос
/ 30 ноября 2011

Проблема в том, что вы удаляете элементы из массива, который вы просматриваете.Согласно Javadoc:

int size() 
Returns the number of elements in this collection.

Это число, которое при удалении элементов из коллекции будет больше, чем фактический размер коллекции, что приведет к выходу за пределы.

Вам необходимо использовать итератор для обхода коллекций, а затем использовать iterator.remove () для удаления элементов из коллекции во время ее обхода.

0 голосов
/ 30 ноября 2011

Мне кажется, что player.getBullets (). Remove (i);удаляет что-то, но вы продолжаете цикл.Вы должны выйти из внутреннего цикла for после System.out.println ...

0 голосов
/ 30 ноября 2011

В вашем коде вы удаляете элементы из списка, который, как мне кажется,

 aliens.getAliens().remove(j); // alien dies
 player.getBullets().remove(i)

Может случиться так, что вы продолжаете цикл во внутреннем цикле, пока условие внешнего цикла недопустимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...