2010-03-17 17 views
5

Tôi thực hiện một trò chơi bắn em bé lên .. Nó hoạt động bình thường nhưng tôi cũng muốn thực hiện nếu đám cháy giao nhau chúng sẽ biến mất. Tôi có hai danh sách cho đạn Player và cho đạn máy tính ... Nhưng nếu tôi có nhiều viên đạn từ máy tính hoặc ngược .Here vòng lặp của tôiJava 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; 

      } 

     } 

    } 

Đây là trò chơi của tôi mà Woking các thuật toán ... http://rapidshare.com/files/364597095/ShooterGame.2.6.0.jar

+2

Nếu 'intersects' hoạt động như mong đợi, bạn không cần hai thử nghiệm' if' riêng biệt, phải không? –

+1

Nếu bạn muốn xóa bất kỳ thứ gì bạn đang lặp lại, bạn nên sử dụng Iterator và sử dụng phương pháp xóa của nó. –

+0

@Shervin: tại sao? những gì thuận? – Roman

Trả lời

7

Tôi khuyên bạn nên đối với chơi với các bộ đếm vòng lặp từ bên trong vòng lặp. Bạn đang cẩn thận bây giờ, bạn sẽ không cẩn thận sau này ("chúng ta hãy thử một hack ở đây để gỡ lỗi") và kết thúc với lỗi.

Một giải pháp có thể là:

  • kiểm tra xem hai đối tượng giao nhau
  • nếu họ làm, tiết kiệm một cách tham chiếu vào một danh sách riêng của thingsToRemove
  • cuối cùng, đi qua các thingsToRemove và loại bỏ (hoặc được đặt thành 'không' hoặc -1 hoặc bất kỳ phần tử nào tương ứng trong các danh sách cbb
+0

+1. Đây là giải pháp. Nó xử lý không chỉ 1 viên đạn máy tính so với 1 viên đạn va chạm mà còn 1 viên đạn máy tính vs N viên đạn trong cùng một vụ va chạm – Roman

1

việc sửa đổi đơn giản nhất để tránh lỗi logic:

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 khi sử dụng giải pháp của bạn, nó sẽ xóa nếu có giao lộ nhưng nếu người chơi bắn nhiều lửa cháy thì nó sẽ bị nứt .. – Ercan

1

Chạy vòng lạc hậu cũng nên làm như lừa:

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

EDIT: Giải pháp này cũng có thể gặp phải OOBE của. Có một số trường hợp không được giải quyết ... vì vậy tôi phải giới thiệu một trong những giải pháp được xếp hạng cao hơn thay vì điều này.

+0

@Carl giải pháp của bạn cũng cung cấp cho IndexOutOfBoundsException. – Ercan

+0

Bây giờ bạn đề cập đến nó, tôi có thể hiểu làm thế nào. Rất tiếc! Tôi sẽ cập nhật câu trả lời của tôi để phản ánh điều này. –

6

Như đã nêu trong bình luận của Carl, thứ hai nếu cần được dự phòng.

Đối với ngoại lệ IndexOutOfBounds của bạn, điều này được gây ra bởi những điều sau đây: Khi dấu đầu dòng máy tính chạm vào dấu đầu dòng của người chơi, bạn sẽ xóa cả hai khỏi danh sách. Sử dụng continue bạn sau đó tiếp tục so sánh cùng một dấu đầu dòng máy tính với các dấu đầu dòng còn lại. Tuy nhiên, viên đạn máy tính đó đã bị xóa trước đó! Do đó, tôi đề nghị bạn break thay vì continue, sau đó dấu đầu dòng máy tính tiếp theo được chọn cho giao lộ với các dấu đầu dòng.

Khi gợi ý bằng mã Roman, bạn nên giảm thêm bộ đếm vòng ngoài, khi bạn giảm kích thước danh sách bằng cách xóa một trong các dấu đầu dòng. Do đó, những gì được sử dụng để được viên đạn # 3 là trong lần lặp tiếp theo những gì trước đây là viên đạn # 4. Vì vậy, sau khi break bạn không muốn tăng số lượt truy cập của vòng lặp bên ngoài.

+0

+1 Tôi không thể hiểu lý do ngoại lệ xảy ra trước khi đọc câu trả lời của bạn. Bây giờ tôi thấy ít nhất 1 trường hợp: khi anh so sánh viên đạn máy tính cuối cùng với các viên đạn khác, sau đó loại bỏ viên đạn máy tính cuối cùng, và sau đó tiếp tục so sánh, ngoại lệ được ném ra. – Roman

0

n opinin của tôi, bạn có thể viết theo cách này

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

ở đâu sai – neverend

+0

Xin chào ... Tôi đã sử dụng ý tưởng của bạn cho cb.size() -1 ad it làm việc trong mã ban đầu của tôi ... Nhưng có lẽ nó cho bất kỳ lỗi nào nhưng tôi đã trả nó 10 lần và nó không đưa ra lỗi))) – Ercan

+0

@ Không nhận được lỗi không phải là bằng chứng hợp lệ chính xác (hợp lý). Nếu bạn muốn so sánh từng viên đạn với mỗi viên đạn máy tính, bạn cần một thuật toán 2 vượt qua như được mô tả bởi @lorenzog (Nếu bạn có o * ba vụ va chạm *, hai viên đạn sẽ bị xóa, thứ ba không) –

1

Vấn đề với mã của bạn là bạn đang thay đổi kích thước của danh sách cb bất cứ khi nào bạn tìm thấy một ngã tư, nhưng sau đó tiếp tục sử dụng các chỉ số tương tự. Ví dụ: nếu cb có 3 phần tử và b có 4 và dấu đầu dòng thứ 3 (chỉ mục = 2) cắt đầu đạn của người chơi đầu tiên, kích thước của cb được giảm xuống còn 2.Khi bạn tiếp tục kiểm tra viên đạn thứ hai đối với viên đạn máy tính thứ ba, chỉ còn lại hai mục trong cb và trò chơi bị treo.

Tóm lại, lặp lại danh sách và sửa đổi chúng cùng một lúc là điều khó khăn.

Điều khác cần lưu ý là nếu, ví dụ, một viên đạn máy tính giao nhau với hai viên đạn của người chơi, cả ba viên đạn đều phải bị xóa. Nhưng nếu viên đạn máy tính bị xóa khi nó gặp viên đạn đầu tiên, viên đạn thứ hai sẽ vẫn còn.

Thực tế, có thể có chuỗi đạn chạm vào nhau, vì vậy việc xóa bất kỳ thứ gì trong danh sách trước khi bạn thực hiện tất cả các giao lộ có thể dẫn đến kết quả sai.

Sau một thời gian dài vui vẻ suy nghĩ về điều này, đây là những gì tôi muốn làm. Nó đảm bảo rằng mọi thứ cần xóa sẽ bị loại bỏ và không phụ thuộc vào việc index-munging.

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;