2015-06-16 5 views
2

В качестве предисловия я искал форумы, но ничего не нашел в связи с моей конкретной ситуацией. Я только начал изучать Java около недели назад, и это мой первый набег на объектно-ориентированное программирование.Удаление элементов из ArrayList при столкновении (Java)?

Я строю основную игру (думаю, что это как космические захватчики, когда дело доходит до механики). У меня есть класс «Projectile», класс «FallingThings» (который является родительским классом для классов, которые у меня есть для объектов, падающих («Деньги, друг, враг»)). Каждый выстреливаемый снаряд хранится в ArrayList и как каждый экземпляр Money, Friend и Enemy (каждый в своем собственном ArrayList).

Проблема возникает, когда я реализую обнаружение столкновения. Во-первых, для создания механизма столкновения требуется несколько пулей (я думаю, что я мог бы просто испортить некоторые цифры здесь, но я не уверен на 100%). Теперь, иногда после того, как я запускаю несколько пуль (и они давно ушли), обнаружено столкновение без того, что я запускаю еще одну пулю, и объект FallingThings исчезает с экрана. Кроме того, в другое время сразу исчезают сразу несколько объектов. Самое странное, что все это непоследовательно и не всегда воспроизводимо одинаково. Однако мои столкновения с персонажем игрока отлично работают.

У кого-нибудь есть идеи относительно того, как я могу это исправить? Мой код ниже:

Метод в классе «FallingThings» (в ArrayList определены в ClassClass (основной класс)).

public void checkBulletCollision(Rectangle rectangle) { 

    for (int j = 0; j < Character.getProjectiles().size(); j++) { 
     Projectile p = (Projectile) Character.getProjectiles().get(j); 
     if (p.isVisible() == true) { 

      for (int i = 0; i < StartingClass.getMoneys().size(); i++) { 
       Money m = (Money) StartingClass.getMoneys().get(i); 
       if (m.getR().intersects(rectangle)) { 
        m.remove(i); 
        System.out.println("bullet collision"); 
       } 
      } 
      for (int i = 0; i < StartingClass.getEnemies().size(); i++) { 
       Enemy e = (Enemy) StartingClass.getEnemies().get(i); 
       if (e.getR().intersects(rectangle)) { 
        e.remove(i); 
       } 
      } 
      for (int i = 0; i < StartingClass.getFriends().size(); i++) { 
       Friend f = (Friend) StartingClass.getFriends().get(i); 
       if (f.getR().intersects(rectangle)) { 
        f.remove(i); 
       } 
      } 
     } 
    } 
} 

Мой метод обновления для снарядами:

public void update() { 
    y -= speedY; 
    if (y < 0) { 
     visible = false; 
    } 
    rectangle.setBounds(getRectangle()); 
} 

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

Большое вам спасибо за помощь! =)

+0

Одна вещь, которую нужно учитывать, когда вам нужно перебирать список и удалять элементы в нем, убедитесь, что вы итерации спускаетесь с List.size() до 0. funky things происходят, когда вы удаляете элемент из списка во время цикла через него в порядке возрастания. – jmcg

+0

Я бы использовал фактический Итератор, у которого есть метод remove(). Не нужно даже думать об индексах в этом случае. – slipperyseal

+0

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

ответ

1

Я подозреваю, что у вас проблемы, потому что вы удаляете элементы из списка по индексу, перебирая этот список. Удаление элементов приводит к тому, что счетчик индексов выходит из привязки. Попробуйте использовать фактический Iterator. Не нужно даже думать об индексах. Iterator имеет метод вынимается для таких ситуаций ..

Iterator<Enemy> iterator = StartingClass.getEnemies().iterator(); 
while (iterator.hasNext()) { 
    Enemy e = iterator.next(); 
    if (e.getR().intersects(rectangle)) { 
     iterator.remove(); 
    } 
} 
+0

Спасибо, что ответили! Я использовал этот точный итератор вместо использования индексов, но у меня по-прежнему возникают те же проблемы, иногда с одновременным исчезновением нескольких объектов и случайным запуском столкновения пули даже без пули. Несмотря на это, я буду поддерживать итератор для простоты и эффективности, но программа по-прежнему делает сумасшедшие вещи. –

+0

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

+0

в порядке, так что, по-моему, сейчас происходит то, что он циклически перемещается по всем петлям и удаляет все экземпляры, которые находятся на экране. Однако разве это не должно произойти, поскольку границы прямоугольника и столкновения будут разными? Кажется, что программа игнорирует прямоугольник (или моя реализация обнаружения столкновений отключена, что кажется более вероятным). Согласитесь ли вы, что это может быть так, или я не в курсе? Я заменил for для циклов итераторами, чтобы избавиться от проблемы индекса. –

0

Я не понимаю, что m.remove делает, вы получите элемент из списка, а затем вызвать «удалить» по этому вопросу. вы хотите удалить его из списка?

StartingClass.getMoneys().remove(i); 
+0

Да, я хочу удалить его из списка. Когда я попытался удалить его, он бросил ошибку при отображении, но разрешил мне вызвать метод «удалить» (который присутствует в классе «День»), который удаляет его экземпляр. –

+0

Пожалуйста, покажите метод. –

+0

Вот метод в классе денег: \t общественного недействительными удалить (INT I) { \t \t StartingClass.getMoneys() удалить (я);. \t} –

0

Похоже, проблема заключается в том, что вы позволяете запускать все типы циклов. Таким образом, даже после удаления Денег с вашим снарядом вы собираетесь на удаление, а Enemy и Friend также с тем же снарядом, что возможно, если этот снаряд уволен из чего-либо большего или из .44 magnum. Во всяком случае, мне, похоже, вам нужно разбить итерацию, как только вы удалите один элемент с одним снарядом .. так что ваш код должен быть как (использование дженериков и усовершенствован для петель):

foreachprojectile: 
    for(Projectile projectile : Character.getProjectiles()){ 
     if (projectile.isVisible() == true) { 

      Iterator<Money> iterator = StartingClass.getMoneys().iterator(); 
      while (iterator.hasNext()) { 
       Money m = iterator.next(); 
       if (m.getR().intersects(rectangle)) { 
        iterator.remove(); 
        projectile.setVisible(false); // or any other method that does similar 
        break foreachprojectile; //Found a hit, so do not 
        //look for any more hits with current projectile 
       } 
      } 
      //And so on.. 
     } 
    } 

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

0

Я понял, что было не так, и исправил проблему.Оказывается, проблема не в моей реализации циклов for (хотя использование listIterator еще более эффективно и менее подвержено ошибкам, поэтому я все же решил изменить этот аспект моего кода), а скорее в реализации моего обнаружения столкновения. Я забыл, что снарядом и прямоугольником (для снаряда) являются два разных объекта, и поэтому прямоугольник не двигался с снарядом, что приводило к возникновению всех проблем.

Я решил проблему, покрасив прямоугольник на экран, чтобы проверить, как он себя ведет, и, конечно же, он просто остался в одном месте, не двигаясь с помощью снаряда. Я внесла некоторые изменения в метод updateile(), чтобы при вызове прямоугольник перемещался с помощью пули. Это привело к правильному обнаружению столкновений и функционирующей программе!

Большое вам спасибо за помощь, я многому научился здесь, написав эффективный код и методы отладки! Я очень ценю это! =)

Смежные вопросы