0
\$\begingroup\$

I'm building a very simple Java game where a player rectangle fires bullet rectangles at enemy rectangles. When a single bullet is on screen, it always correctly collides with enemies. When multiple bullets are on screen, they often go right through the enemies without triggering a collision. The only way to get the collision to work is to run very far away from the enemy; if the bullet travels a very far distance before hitting the enemy, the collision will work with multiple bullets on screen.

I tried writing a method to calculate a new rectangle that extends the colliding sprites' previous location to its current location, and then checking these extended rectangles for collisions, but to no avail.

Below are the methods I'm using in the sprite parent class to create these extended rectangles and to check for intersection:

public boolean movingIntersects(GameEntity g) {
    return this.getMovingRectangle().intersects(g.getMovingRectangle());
}

public Rectangle getMovingRectangle() {
    Rectangle r = new Rectangle();
    r.x = Math.min(x, prevX);
    r.y = Math.min(y, prevY);
    r.width = Math.abs(x - prevX) + width;
    r.height = Math.abs(y - prevY) + height;
    //System.out.println(this + " " + r);
    return r;
}

This is the code I'm using in the actionPerformed method to handle moving and managing the sprites. Variable p is the player, keys holds the keys being pressed, tm holds the Timer that triggers the actionPerformed:

public void actionPerformed(ActionEvent e) {
// pause game if necessary
if (keys.contains(KeyEvent.VK_ESCAPE)) {
    paused = !paused;
    keys.remove(KeyEvent.VK_ESCAPE);
}
if (!paused) {
    // Setup player movement
    p.movement = 0;
    if (keys.contains(KeyEvent.VK_W)) {
    p.movement |= GameEntity.UP;
    }
    if (keys.contains(KeyEvent.VK_S)) {
    p.movement |= GameEntity.DOWN;
    }
    if (keys.contains(KeyEvent.VK_A)) {
    p.movement |= GameEntity.LEFT;
    }
    if (keys.contains(KeyEvent.VK_D)) {
    p.movement |= GameEntity.RIGHT;
    }
    // Setup bullets
    p.framesToNextFire = Math.max(0, --p.framesToNextFire);
    if (p.framesToNextFire == 0) {
    Bullet b = new Bullet(this, 0, 0, 0, p.bulletSpeed);
    b.x = p.x + (p.width / 2) - (b.width / 2);
        b.y = p.y + (p.height / 2) - (b.height / 2);
    if (keys.contains(KeyEvent.VK_UP)) {
        b.movement = GameEntity.UP;
        p.bullets.add(b);
        p.framesToNextFire = p.coolDown;
    } else if (keys.contains(KeyEvent.VK_DOWN)) {
        b.movement = GameEntity.DOWN;
        p.bullets.add(b);
        p.framesToNextFire = p.coolDown;
    } else if (keys.contains(KeyEvent.VK_LEFT)) {
        b.movement = GameEntity.LEFT;
        p.bullets.add(b);
        p.framesToNextFire = p.coolDown;
    } else if (keys.contains(KeyEvent.VK_RIGHT)) {
        b.movement = GameEntity.RIGHT;
        p.bullets.add(b);
        p.framesToNextFire = p.coolDown;
    }
    }

    // Move GameEntities
    if (enemies.size() > 0) {
    // move player
    p.move(GameEntity.CONSTRAIN);
    // move enemies
    for (Enemy en : enemies) {
        en.move(GameEntity.CONSTRAIN);
    }
    // move bullets
    Iterator<Bullet> itB = p.bullets.iterator();
    while (itB.hasNext()) {
        Bullet b = itB.next();
        //System.out.println(b.x + ":" + b.y);
        if (b.move(GameEntity.REMOVE)) {
        itB.remove();
        }
    }
    // Check for shot enemies
    itB = p.bullets.iterator();
    Iterator<Enemy> itE = enemies.iterator();
    while (itB.hasNext()) {
        Bullet b = itB.next();
        while (itE.hasNext()) {
        Enemy m = itE.next();
        if (b.movingIntersects(m)) {
            m.health -= b.health;
            itB.remove();
            if (m.health <= 0) {
            int points = (int) (m.intelligence * m.speed * 100);
            System.out.println(m.intelligence + " + " + m.speed + " = " + points);
            score += points;
            itE.remove();
            }
            break;
        }
        }
    }

    // Check for dead player
    itE = enemies.iterator();
    while (itE.hasNext()) {
        Enemy m = itE.next();
        if (m.intersects(p)) {
        // Player is dead
        tm.stop();
        // Show score
        message = "Game Over";
        paused = true;
        // Reset game
        level = 1;
        score = 0;
        startLevel();
        tm.start();
        break;
        }

    }
    // Draw the screen
    repaint();
    } else {
    tm.stop();
    p.bullets.clear();
    repaint();
    level++;
    startLevel();
    tm.start();
    }
}
}
\$\endgroup\$
2
\$\begingroup\$

The reason this code fails when you have more than one bullet is that for each bullet, you go through each enemy to check for a collision. The piece of code that initializes itE (the enemy iterator) is outside the bullet loop, so what is actually happening is that you are checking all the enemies on the first bullet only. Each check after that the enemy iterator is already at the end of the list, so you are not checking anything. Move the line: Iterator itE = enemies.iterator(); down to inside the while loop, and that should fix your first problem.

There is a second problem you are not seeing yet, which is that you remove any enemy you collide against from the list with the line itE.remove(). This means that each enemy can only get hit once per frame, even if multiple bullets hit it. Remove the line itE.remove() from your code, it is not required and will cause you problems.

\$\endgroup\$
  • \$\begingroup\$ Tom this is genius. But one question about the itE.remove(): at this point I want a single bullet to eliminate a single enemy, so shouldn't I be removing the enemy from the list? What should I be doing instead to "kill" the enemy and remove it from the list of enemies to be rendered? \$\endgroup\$ – iopener May 17 '14 at 6:16
  • \$\begingroup\$ It turns out that I needed to keep the itE.remove() line or else my enemies never got removed from the list of enemies to render. Thanks again for finding that glitch in my code. \$\endgroup\$ – iopener May 21 '14 at 21:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.