Java IndexOutOfBoundsException
我做了一个射击游戏。它可以正常工作,但我也想实现,如果火相交,它们就会消失。我有两个列表,一个是玩家子弹,另一个是电脑子弹……但如果我有更多的电脑子弹或是反向子弹,这里是我的循环Java IndexOutOfBoundsException,java,Java,我做了一个射击游戏。它可以正常工作,但我也想实现,如果火相交,它们就会消失。我有两个列表,一个是玩家子弹,另一个是电脑子弹……但如果我有更多的电脑子弹或是反向子弹,这里是我的循环 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)) {
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;
}
}
}
for(int i=0;i
这是我的游戏,它的工作算法。。。
避免逻辑错误的最简单修改:
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--);
}
}
}
for(int i=0;i
反向运行循环也可以做到这一点:
编辑:此解决方案也可能遇到OOBE。有一些未处理的案件。。。因此,我必须推荐一种级别更高的解决方案,而不是这个。正如卡尔评论中所述,第二个if应该是多余的 至于IndexOutOfBounds异常,这是由以下原因引起的: 当一个计算机子弹击中一个玩家子弹时,你将从列表中删除这两个。使用
continue
继续将同一个计算机项目符号与其他玩家项目符号进行比较。然而,那颗计算机子弹之前已经被移除了!因此,我建议您中断
而不是继续
,然后检查下一个计算机项目符号是否与玩家项目符号相交
正如Roman用他的代码暗示的那样,您应该进一步减少外循环的计数器,因为您通过删除一个项目符号来减少列表大小。因此,在下一次迭代中,以前是bullet#3的是bullet#4。因此,在
中断之后
您不希望外部循环计数器的增量。我强烈建议不要从循环本身内部使用for循环计数器。你现在很小心,以后就不会小心了(“让我们在这里尝试一个黑客来调试”),结果会出现bug
一种解决办法可以是:
- 检查两个对象是否相交
- 如果有,则将引用保存到
thingsToRemove
- 最后,检查
并删除thingsToRemove
和cb
列表中的相应元素(或设置为“null”,或b
或其他)-1
- 依我看,你可以这样写
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);
}
代码的问题是,每当您找到交叉点时,您都会更改列表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;
ArrayList newB=新的ArrayList(b);
ArrayList newCB=新ArrayList(cb);
用于(项目符号pBullet:b){
用于(项目符号cBullet:cb){
if(pBullet.rect.相交(cBullet.rect)){
拆下新的(pBullet);
新cb.移除(cBullet);
}
}
}
cb=新cb;
b=新的;
如果相交
工作正常,则不需要两个独立的If
测试,否?如果您想删除正在迭代的任何内容,您应该使用迭代器并使用其删除方法。@Roman-优点包括避免类似这样的错误。这比我想象的要复杂得多:您不能过早删除任何项目符号,以免丢失碰撞。请删除空行+1在阅读您的答案之前,我无法理解为什么会发生异常。现在我看到了至少一种情况:当他将最后一个计算机项目符号与其他项目符号进行比较,然后移除最后一个计算机项目符号,然后继续比较时,抛出异常。这就是解决办法。它不仅可以处理1个计算机子弹与1个用户子弹的碰撞,还可以处理1个计算机子弹与N个用户子弹在同一位置的碰撞。。。我使用了你对cb.size()-1的想法,它在我的原始代码中起作用…但可能会有任何错误,但我支付了10次,它没有给出错误。)@Meko没有得到错误并不能有效地证明它(逻辑上)是正确的。如果你想将每个用户项目符号与每个计算机项目符号进行比较,你需要一个由@lorenzog描述的2遍算法(如果你有o个三重碰撞,两个项目符号将被删除,第三个项目符号不会被删除)HI like@Carlos sad它不会删除一些项目符号//我没有识别,我的游戏速度很快,子弹很多。我把它改成了一发子弹,一些子弹没有删除。但在游戏中你无法识别:)@Carl你的解决方案也给了IndexOutofBoundsSexception。既然你提到了它,我就明白了怎么做了。哎呀!我将更新我的答案以反映这一点。@Roman在使用您的解决方案时,如果存在交叉点,但
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;