2010-03-17 11 views
5

Zrobiłem małą strzelankę. Działa to normalnie, ale chcę też wdrożyć, jeśli pożary przecinają się, znikną. Mam dwie listy dla graczy oraz dla kul kul komputerowych ... Ale jeśli mam więcej kul z komputera lub do tyłu .Tutaj moja pętlaJava IndexOutOfBoundsException

 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; 

      } 

     } 

    } 

To moja gra, która Woking algoritms ... http://rapidshare.com/files/364597095/ShooterGame.2.6.0.jar

+2

Jeśli 'przecina się 'działa tak, jak można by oczekiwać, nie powinieneś potrzebować dwóch oddzielnych testów" jeśli ", nie? –

+1

Jeśli chcesz usunąć cokolwiek, co powtarzasz, powinieneś użyć Iteratora i użyć jego metody usuwania. –

+0

@Shervin: dlaczego? jakie zalety? – Roman

Odpowiedz

7

Bardzo polecam przeciwko podczas gry z licznikami pętli for z samej pętli. Teraz jesteś ostrożny, nie będziesz ostrożny później ("spróbujmy włamać się tutaj, aby debugować") i skończymy z błędami.

Jednym z rozwiązań mogłoby być:

  • sprawdzić, czy dwa obiekty przecinają
  • Jeśli tak, zapisz odniesienie do oddzielny listy thingsToRemove
  • wreszcie przejść przez thingsToRemove i usunąć (lub ustaw na "null" lub -1 lub cokolwiek innego) odpowiednie elementy w i b listach
+0

+1. To jest rozwiązanie. Zajmuje się nie tylko 1 pociskiem komputerowym w stosunku do 1 użytkownika, ale także 1 pociskiem komputerowym w stosunku do N pocisków użytkownika w tym samym miejscu kolizji – Roman

1

najprostsza modyfikacja uniknąć błąd logiczny:

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

@Roman, gdy używasz rozwiązania, które usuwa, jeśli jest przecięcie, ale jeśli gracz odpala repetetalnie dużo ognia, to się kręci .. – Ercan

1

uruchamiając pętle wstecz należy również wykonać trick:

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

EDIT: To rozwiązanie może również wystąpić OOBE. Jest kilka nieobsłużonych spraw ... więc muszę zalecić raczej rozwiązanie o wyższej pozycji niż to.

+0

@Carl twoje rozwiązanie daje również IndexOutOfBoundsException. – Ercan

+0

Teraz, kiedy o tym wspomniałeś, mogę zrozumieć, jak. Ups! Zaktualizuję moją odpowiedź, aby to odzwierciedlić. –

6

Jak stwierdzono w komentarzu Carla, drugi powinien być zbędny.

Jeśli chodzi o wyjątek IndexOutOfBounds, przyczyną jest: Gdy punktor komputerowy trafi punktor gracza, usuwasz oba z list. Następnie kontynuuj porównywanie tego samego wypunktowania z pozostałymi punktorami gracza. Jednak ten punktor komputerowy został już wcześniej usunięty! Dlatego sugeruję, że zamiast , zamiast następnego pocisku komputerowego sprawdzany jest punkt przecięcia z punktorami gracza.

Roman sygnalizując kod, powinieneś dodatkowo zmniejszyć licznik zewnętrznej pętli, zmniejszając rozmiar listy, usuwając jeden z pocisków. W związku z tym, co było bulletem # 3, znajduje się w kolejnej iteracji, która poprzednio była punktem # 4. Więc po break nie chcesz zwiększać licznika zewnętrznej pętli.

+0

+1 Nie mogłem złapać przyczyny wyjątku przed przeczytaniem odpowiedzi. Teraz widzę co najmniej 1 przypadek: kiedy porównuje ostatnią kulę komputerową z innymi punktorami, usuwa ostatni punktor komputerowy, a następnie kontynuuje porównywanie, wyjątek jest generowany. – Roman

0

n mój opinin, można napisać w ten sposób

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); 
    } 
+0

gdzie jest źle – neverend

+0

Cześć ... Użyłem twojego pomysłu na cb.size() -1 reklama to pracowałem w moim oryginalnym kodzie ... Ale może to daje jakiś błąd, ale zapłaciłem 10 razy i to nie daje błędu))) – Ercan

+0

@Meko nie otrzymanie błędu nie jest ważnym dowodem, że jest (logicznie) poprawny. Jeśli chcesz porównać każdy pocisk użytkownika z każdym pociskiem komputerowym, potrzebujesz algorytmu 2-przebiegowego opisanego przez @lorenzog (jeśli masz * potrójną kolizję *, dwa pociski zostaną usunięte, a trzecia nie) –

1

Problem z kodem jest to, że są zmiany wielkości listy cb gdy znajdziesz przecięcie, ale następnie kontynuować przy użyciu tego samego indeksu. Na przykład, jeśli cb ma 3 elementy, a b ma 4, a trzeci (indeksu = 2) pocisk komputerowy przecina pocisk pierwszego gracza, rozmiar cb jest zmniejszony do 2.Kiedy przejdziesz następnie do sprawdzenia kuli drugiego gracza przeciwko trzeciej kuli komputerowej, w cb pozostaną tylko dwa elementy, a gra się zawiesza.

Krótko mówiąc, pętle nad listami i modyfikowanie ich w tym samym czasie jest trudne.

Inną rzeczą, o której należy pamiętać, jest to, że jeśli na przykład pocisk komputerowy przecina się z pociskami dla dwóch graczy, wszystkie trzy powinny zostać usunięte. Ale jeśli pocisk komputera zostanie usunięty, gdy napotka pierwszy pocisk gracza, drugi pocisk gracza pozostanie.

W rzeczywistości mogą istnieć łańcuchy kulek, które dotykają się nawzajem, więc usunięcie czegokolwiek z listy przed wykonaniem wszystkich skrzyżowań może prowadzić do złych wyników.

Po zabawnie długim czasie, myśląc o tym, oto co zrobię. Zapewnia to, że wszystko, co wymaga usunięcia, jest usuwane i nie polega na indeksowaniu.

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; 
Powiązane problemy