Search code examples
javagraphicsgraphics2d

Java Graphics2D - Detecting collisions between two objects


I'm creating a trial game where a spacecraft fires missiles to a stationary enemy spacecraft. The missile moves from left to right, and the enemy spacecraft is positioned on the right side. If a missile hits the enemy craft, it "explodes" (disappears from the screen). My problem is when should I execute the explode method because it is kinda tricky to tell if one of the missiles's plot coincides with that of the enemy craft. In my main program, I have the following:

private void updateMissiles(){
    ArrayList ms = craft.getMissiles();
    for(int i = 0; i < ms.size(); i++){
        Missile m = (Missile) ms.get(i);
        if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()){
            enemcraft.explode();
        }
        if(m.isVisible()){
            m.move();
        }else{
            ms.remove(i);
        }
    }
}

This does not work especially because the missile and the enemy spacecraft have different dimensions (8x5 pixels and 20x20 pixels, respectively). However, when I changed if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()) to simply if(m.getX() == enemcraft.getX()), the program works, but it disregards the y position of the missile and will make the enemy craft explode as long as the missile reaches the same x position of the enemy.

I tried experimenting with different ranges of the x and y positions, but to no avail. Is there an intuitive way to tell when the missile "hits" the enemy craft?


Solution

  • AABB (Axis Aligned Bounding Boxes)

    You have not given much to go by but making a comparison based on position is not going to solve your problem.

    The line

    if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()){
    

    Requires that the missile and enemy have the same position (x,y), there is only one point on the screen that has that coordinate so it's going to be hard to hit. You have effectively made your bad guy and missiles one pixel width and one pixel in height.

    Bounding boxes

    Both the missile and enemy have a size (area) you need to test if these areas hit. Imagine two rectangles each containing the missile and enemy. When these two rectangles overlap you can count that as a collision.

    As I dont know where the x,y of the missile and enemy are (top left or center or something else) I will assume that you use the top left. Nor do I know if the two objects provide a width and height so I will hard code that. (20,20) and for missile (8,5)

    private void updateMissiles () {
        ArrayList ms = craft.getMissiles();
        int mLeft = enemyCraft.getX(); // guessing position is an int . Set the correct type when you copy this
        int mTop = enemyCraft.getY();
        int mRight = mLeft + 20;
        int mBottom = mTop + 20;
    
        for (int i = 0; i < ms.size(); i++) {
            Missile m = (Missile) ms.get(i);
            // only test if both missile and enemyCraft are visible
            // I am guessing that enemyCraft has a isVisible method
            if(m.isVisible() && enemyCraft.isVisible()){
                int mx = m.getX(); // Again I am guessing the type as int
                int my = m.getY();
                if ( ! (my > mBottom || mx > mRight || mx + 8 < mLeft || my + 5 < mTop)) {
                    enemyCraft.explode();
                    ms.remove(i);  // remove missile
                }
            }
            if (m.isVisible()) {
                m.move();
            }
        }
    }
    

    Better fit.

    There is a problem with this method. The missiles and bad guys may not be the same shape as the bounding box. This will result in a collision even if they are not actually touching. But that is easily solved.

    Do the test as above, this will let you know if you should do more testing. When you find a collision divide the two objects into a few smaller bounding boxes and test if they overlap. That will improve the accuracy.