1

对于 IndexOutOfBoundsException:

嗨,我正在制作类似游戏的太空入侵者,当子弹与敌人相撞时我遇到了问题。这是代码:

for (int i = 0; i < enemies.size(); i++) {
    for (int j = 0; j < bullets.size(); j++) {
        if (collidesWith(bullets.get(j), enemies.get(i))) { //Line 81 The Error Occurred here
            enemies.remove(i);
            bullets.remove(j);
            addScore(1);
        }
    }
}

碰撞代码:

public static boolean collidesWith(Entity collider, Entity collided) {
    Rectangle hitBox1 = collider.getHitbox();
    Rectangle hitBox2 = collided.getHitbox();

    return hitBox1.intersects(hitBox2);
}

Hitbox 的代码:

@Override
public Rectangle getHitbox() {
    return new Rectangle(getX(), getY(), getWidth(), getHeight());
}

错误消息:

Exception in thread "Thread-4" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.get(ArrayList.java:411)
at io.github.kjordo711.game.Main.run(Main.java:81)
at java.lang.Thread.run(Thread.java:724)

我认为由 2 颗或更多子弹造成的错误击中了敌人

对于 OutOfMemoryError:

玩家可以在按住 Space 的情况下一次射出太多子弹,子弹将继续射击而不会延迟我可以限制子弹的生成,但问题是即使屏幕上最多 10 颗子弹,错误仍然会发生,我试图延迟它

Thread.sleep(500);

但它只是睡眠所有的游戏线程

4

3 回答 3

3

这是因为您正在删除循环中的对象,这是不正确的,此外ArrayIndexOutOfBoundsException这也可能导致 a ConcurrentModificationExcetion

当您应该从集合中删除对象时,请考虑使用java.util.Iterator接口。

Iterator<Enemy> enemiesIterator = enemies.iterator();
Iterator<Entity> bulletsIterator = bullets.iterator();
while (enemiesIterator.hasNext()) {
    Enemy nextEnemy = enemiesIterator.next();
    while(bulletsIterator.hasNext()) {
        Entity nextBullet = bulletsIterator.next();
        if (colliesWith(nextBullet, nextEnemy) {
            enemierIterator.remove();
            bulletsIterator.remove();
            addScore(1);
        }
    }
}
于 2013-10-06T11:20:37.180 回答
2

问题是您删除了嵌套循环内的对象。一旦你在 处移除一个敌人i,敌人列表就会缩短一个。如果i恰好等于 的旧长度enemies,则后续调用enemies.get(i)将导致异常。由于内部循环没有重新检查i,所以这种情况是可能的。为此添加一个守卫并向后迭代(当您可以随时删除项目时您所做的事情)应该处理异常并避免在删除时跳过碰撞检查:

for (int i = enemies.size()-1 ; i >= 0 ; i--) {
    for (int j = bullets.size()-1 ; j >= 0 && i < enemies.size() ; j--) {
        if (collidesWith(bullets.get(j), enemies.get(i))) {
            enemies.remove(i);
            bullets.remove(j);
            addScore(1);
        }
    }
}
于 2013-10-06T11:19:19.997 回答
0

我将回答您对第二个问题的担忧: usingThread.sleep(...)将阻止当前线程(可能是 EDT),从而冻结您的整个游戏。如果你想避免发射太多子弹,你应该使用System.currentTimeMillis()每次Space击键并将它与最后一个实际发射子弹的键进行比较:

static final int RECOIL = 500; // Minimum ms to wait between two shots
long lastShotMs = 0;

void fireBullet() { // Called when spacebar is pressed
    long shotMs = System.currentTimeMillis();
    if (shotMs - lastShotMs < RECOIL)
        return;
    lastShotMs = shotMs;
    doFireBullet(); // Perform the bullet-firing
}
于 2013-10-06T11:45:15.357 回答