Java IndexOutOfBoundsException - PullRequest
       3

Java IndexOutOfBoundsException

5 голосов
/ 17 марта 2010

Я сделал небольшую игру "Стреляй в них". Она работает нормально, но я хочу также реализовать, если огни пересекаются, они исчезнут. У меня есть два списка для пуль игрока и для пуль компьютера ... Но если у меня есть больше пуль от компьютера или наоборот. Вот мой цикл

     for (int i = 0; i < cb.size(); i++) {
        for (int j = 0; j < b.size(); j++) {
            if (b.get(j).rect.intersects(cb.get(i).rect)) {

                cb.remove(i);
                b.remove(j);


                continue;

            }
            if (cb.get(i).rect.intersects(b.get(j).rect)) {


                b.remove(j);
                cb.remove(i);

                continue;

            }

        }

    }

Это моя игра, в которой просыпаются алгоритмы ... http://rapidshare.com/files/364597095/ShooterGame.2.6.0.jar

Ответы [ 6 ]

7 голосов
/ 17 марта 2010

Я настоятельно рекомендую против играть со счетчиками цикла for внутри самого цикла. Вы осторожны сейчас, вы не будете осторожны позже («давайте попробуем взломать здесь для отладки») и в итоге получим ошибки.

Одним из решений может быть:

  • проверить, пересекаются ли два объекта
  • если это так, сохраните ссылку в отдельном списке thingsToRemove
  • наконец, пройдите через thingsToRemove и удалите (или установите на 'null', или -1 или что-то еще) соответствующие элементы в списках cb и b
6 голосов
/ 17 марта 2010

Как указано в комментарии Карла, второе, если должно быть излишним.

Что касается вашего исключения IndexOutOfBounds, это вызвано следующими причинами: Когда пуля компьютера попадает в пулю игрока, вы удаляете оба из списков. Используя continue, вы продолжаете сравнивать ту же пулю компьютера с остальными пулями игрока. Однако эта компьютерная пуля была уже удалена раньше! Следовательно, я предлагаю вам break вместо continue, затем следующая компьютерная пуля проверяется на предмет пересечения с пулями игрока.

Как Роман намекает на его код, вы должны еще больше уменьшить счетчик внешнего цикла, поскольку вы уменьшили размер списка, удалив одну из пуль. Следовательно, то, что раньше было маркером № 3, на следующей итерации является тем, что раньше было маркером № 4. Поэтому после break вы не хотите увеличивать счетчик внешнего цикла.

1 голос
/ 17 марта 2010

Проблема с вашим кодом заключается в том, что вы меняете размер списка cb всякий раз, когда обнаруживаете пересечение, но затем продолжаете использовать тот же индекс. Например, если cb имеет 3 элемента, а b имеет 4, а третья (индекс = 2) компьютерная пуля пересекает первую пулю игрока, размер cb уменьшается до 2. Когда вы продолжаете проверять пулю второго игрока по третья компьютерная пуля, в cb осталось только два элемента, и игра вылетает.

Короче говоря, зацикливание списков и одновременное их изменение сложно.

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

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

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

ArrayList<Bullet> newB = new ArrayList<Bullet>(b);
ArrayList<Bullet> newCB = new ArrayList<Bullet>(cb);
for (Bullet pBullet : b) {
    for (Bullet cBullet : cb) {
        if (pBullet.rect.intersects(cBullet.rect)) {
            newB.remove(pBullet);
            newCB.remove(cBullet);
        }
    }
}
cb = newCB;
b = newB;
1 голос
/ 17 марта 2010

Запуск циклов назад также должен помочь:

for (int i = cb.size() - 1; i >= 0; i--) {
       for (int j = b.size() - 1; j >= 0; j--) {

РЕДАКТИРОВАТЬ: Это решение также может встретиться с OOBE. Есть некоторые необработанные случаи ... поэтому я должен рекомендовать одно из решений с более высоким рейтингом, а не это.

1 голос
/ 17 марта 2010

самая простая модификация, чтобы избежать логической ошибки:

for (int i = 0; i < cb.size(); i++) {
    for (int j = 0; j < b.size(); j++) {
        if (b.get(j).rect.intersects(cb.get(i).rect)) {
            cb.remove(i--);
            b.remove(j--);
        }
    }
}
0 голосов
/ 17 марта 2010

n Мое мнение, вы можете написать таким образом

   for (int i = cb.size() -1; i >= 0 ; i--) {
            boolean bremoved = false;
        for (int j = b.size() -1 ; j >=0 ; j--) {
            if (b.get(j).rect.intersects(cb.get(i).rect) ||
                cb.get(i).rect.intersects(b.get(j).rect)) {
                  bremoved = true;
                b.remove(j);
            }
        }
        if(bremoved)
            cb.remove(i);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...