Search code examples
javaobjectgraphicsdetectionhit

Java: Hit Detection improperly detecting overlap among two objects


so I have a rowing game in which a boat object must dodge randomly placed obstacle objects using the arrow keys. If the boat hits one of the obstacles, the boat takes a random amount of damage. The boat is a 27x52 picture (with 2 pixels of nothing on either side so the code shows 2-25) and obstacles are rectangles.

I have hit detection working for the most part; however, whenever the boat is on the right side of a rectangle that is taller than it is wide, it'll take damage, even if the boat is about 5-10 pixels away from the right edge of the rectangle. Refer to this image for a better understanding of the issue: https://i.sstatic.net/Wtm4k.jpg

In my code, I create an array of 15 obstacles. Obstacles take the parameters(Color color, int damageDealt, int xPos, int yPos, int width, int height, boolean hasHit).

//Create array of obstacles
for(int x = 0; x < 15; x++) {
        obstacles[x] = new Obstacle((new Color(rand.nextInt(81), rand.nextInt(51), rand.nextInt(51))), rand.nextInt(21) + 10, rand.nextInt(601), 
            (-x * (rand.nextInt(51) + 31)), (rand.nextInt(31) + 5), (rand.nextInt(31) + 5), false); 
    }

Here is the hit detection code (This is in a for loop cycling through the array of obstacle objects:

for(int y = 2; y <= 25; y++) {
                //Obstacles hit detection
                for(int z = 0; z <= obstacles[x].getw(); z++) {           
                      if(boat.getx() + y == obstacles[x].getx() + z && boat.gety() == obstacles[x].gety()) {
                            if(!obstacles[x].getDamaged()) {
                                 boat.setHealth(boat.getHealth() - obstacles[x].getdmg());
                                 obstacles[x].setDamaged(true);
                            }
                      }             
                }

Right now it cycles through the boat's x values, 2 to 25, instead of 0 to 27 because of the two pixels of nothing on either side. It then cycles through the obstacle's x values(xPos to xPos+width) and sees if any of those values match. If there is a match, and the y-values match, then the boat will take damage. Keep in mind this only happens when the boat is on the right side of an obstacle and the obstacle is taller than it is wide. I do not see a problem with my code yet I cannot figure out a solution for my error. Thanks.

EDIT: Here is the code for the boat and obstacle classes.

import java.awt.Color;
import java.awt.Rectangle;

public class Obstacle {
    private int dmg, xPos, yPos, height, width;
    private Color color;
    private boolean hasDamaged;

    public Obstacle(Color hue, int damage, int x, int y, int w, int h, boolean damaged) {
        dmg = damage;
        xPos = x;
        yPos = y;
        width = w;
        height = h;
        color = hue;
        hasDamaged = damaged;
    }

    public boolean getDamaged() {
        return hasDamaged;
    }
    public void setDamaged(boolean damaged) {
        hasDamaged = damaged;
    }

    public Color getColor() {
        return color;
    }

    public int getdmg() {
        return dmg;
    }
    public void setdmg(int damage) {
        dmg = damage;
    }

    public int getx() {
        return xPos;
    }
    public void setx(int x) {
        xPos = x;
    }

    public int gety() {
        return yPos;
    }
    public void sety(int y) {
        yPos = y;
    }

    public int getw() {
        return width;
    }
    public void setw(int w) {
        width = w;
    }

    public int geth() {
        return height;
    }
    public void seth(int h) {
        height = h;
    }

    public Rectangle getBounds() {
        return new Rectangle(xPos, yPos, width, height);
    }
}

And the boat class:

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.Rectangle;

public class Boat {

private int hp, xPos, yPos, dx;
private BufferedImage boatPic;

public Boat(BufferedImage img, int health, int x, int y, int velX) {
    boatPic = img;
    hp = health;
    xPos = x;
    yPos = y;
    dx = velX;
}


public BufferedImage getImage() {
    return boatPic;
}
public void setImage(BufferedImage img) {
    boatPic = img;
}

public int getHealth() {
    return hp;
}
public void setHealth(int health) {
    hp = health;
}

public int getx() {
    return xPos;
}
public void setx(int x) {
    xPos = x;
}

public int gety() {
    return yPos;
}
public void sety(int y) {
    yPos = y;
}

public int getdx() {
    return dx;
}
public void setdx(int velX) {
    dx = velX;
}

public Rectangle getBounds() {
    return new Rectangle(xPos, yPos, 25, 49);
}    
}

Solution

  • If your ship alway facing the same direction, you can check collision much easier.

    By creating a method for your ship and for the obstacles that returns a rectangle with the size of your object.

    public Rectangle getBounds() {
        return new Rectangle(shipPosX, shipPosY, widht, height);
    }
    

    Like this. This way you can test collision in one line:

    getBounds().intersects(obstacle.getBounds());
    

    This will return true if they intersect.

    If you want to be more precise, or want different cases for collisions from different directions, you can create a rectangle for different parts of your ship, like it's body and wings.

    public Rectangle getRightWingBound(){}
    public Rectangle getLeftWindBound(){}
    

    and so on.