2010-03-17 121 views
5

我做了一個小射擊,game..It工作正常,但我想還實現了,如果火災相交,他們就會消失。我有兩個列表播放子彈和計算機子彈......但是,如果我從電腦更多的子彈或逆轉。在這裏我的循環的Java 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; 

      } 

     } 

    } 

這是我的遊戲,沃金algoritms ... http://rapidshare.com/files/364597095/ShooterGame.2.6.0.jar

+2

如果'intersects'工作正如人們所期望,你不應該需要兩個獨立的'if'測試,不是嗎? – 2010-03-17 10:02:13

+1

如果你想刪除任何你正在迭代的東西,你應該使用Iterator並使用它的remove方法。 – 2010-03-17 10:05:07

+0

@Shervin:爲什麼?有什麼優點? – Roman 2010-03-17 10:09:41

回答

7

我強烈建議與打循環計數器從環本身。你現在小心了,稍後你不會小心(「讓我們試着在這裏進行調試」)並最終發現錯誤。

一種解決方案可能是:

  • 檢查是否兩個對象相交
  • 如果他們這樣做,保存參考到的thingsToRemove
  • 一個單獨名單終於,經過thingsToRemove和刪除(或設置爲「空」,或-1或其他)在cbb列出了相應的元件
+0

+1。這是解決方案。它不僅處理1個電腦子彈與1個用戶子彈的碰撞,而且還有1個電腦子彈與N個用戶子彈在同一個地方碰撞 – Roman 2010-03-17 10:38:29

1

最簡單的修改,以避免邏輯錯誤:

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使用你的解決方案時,它刪除,如果有交集,但如果播放器重複firedetraly火它刷新.. – Ercan 2010-03-17 14:50:21

1

運行循環落後也應該做的伎倆:

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

編輯:該解決方案還可以遇到OOBE的。有一些未處理的情況...所以我必須推薦一個更高等級的解決方案,而不是這個。

+0

@Carl你的解決方案也給IndexOutOfBoundsException。 – Ercan 2010-03-17 14:47:21

+0

現在你提到它,我可以理解如何。哎呀!我會更新我的答案以反映這一點。 – 2010-03-18 13:21:22

6

正如卡爾的評論指出,第二是否應該是多餘的。

至於你IndexOutOfBounds例外,這是由以下因素導致: 當計算機子彈擊中玩家的子彈,你無論是從列表中刪除。然後使用continue繼續比較相同的計算機項目符號和其餘的項目符號。但是,那個電腦子彈已經被刪除了!因此,我建議你break而不是continue,那麼接下來的計算機子彈檢查被玩家的子彈交集。

於與他的代碼,你應該進一步降低外循環的計數器,當你通過移除子彈減少一個列表的大小羅馬提示。因此,以前是子彈#4的是第3號子彈。所以在break之後,你不需要增加外環的計數器。

+0

+1我無法理解在閱讀您的答案之前發生異常的原因。現在我看到至少有一種情況:當他比較上一個計算機項目符號和其他項目符號時,然後刪除最後一個計算機項目符號,然後繼續比較,則引發異常。 – Roman 2010-03-17 10:13:38

0

ñ我opinin,你可以用這種方式

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

哪裏出錯了 – neverend 2010-03-17 11:04:04

+0

嗨...我用你的想法做了cb.size()-1工作在我原來的代碼...但也許它給了任何錯誤,但我付了10次,它不給錯誤))) – Ercan 2010-03-17 12:18:40

+0

@Meko沒有得到一個錯誤不是一個有效的證明,它是(邏輯上)是正確的。如果要將每個用戶項目符號與每個計算機項目符號進行比較,則需要按照@lorenzog所述的2-pass算法(如果您有o * triple-collision *,兩個項目符號將被刪除,第三個項目不會被刪除) – 2010-03-17 12:55:04

1

寫你的代碼的問題是,您要更改列表cb的,只要你找到一個交叉點,但隨後繼續使用同一指數的大小。例如,如果cb有3個元素,b有4個,並且第3個(索引= 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; 
相關問題