javageometrycollision-detection

How can I prevent two Rectangle2D from overlapping?


I am trying to create a Vampire survivor type game, and I am currently creating the logic of the enemies, but I have found a problem, and that is that they are able to overlap each other, to a point where you don't even notice that there are 2, which is uncomfortable because I need them to be able to collide and maybe be one on top of the other slightly, but not to that extreme.

I have tried to use a code to solve the collisions, but when I try to do it these two just move one after the other pushing each other, even so I feel that my code is not done in the best way.

Enemy Movement:

public void move(double playerX, double playerY, double fps, List<Enemies> enemiesList){
        double angle = Math.atan2(playerY - y, playerX - x);
        x += Math.cos(angle) * speed / fps;
        y += Math.sin(angle) * speed / fps;
        hitbox.setFrame(x, y, 40, 40);
        for (int i = 0; i < enemiesList.size(); i++) {
            if (this == enemiesList.get(i)) {

                continue;
            }
            if (hitbox.intersects(enemiesList.get(i).getHitbox())) {

                resolveCollition(enemiesList.get(i).getHitbox());
            }
        }

    }

the attempt to solve it

private void resolveCollition(Rectangle2D.Double otherHitbox) {
        double overX;
        double overY;
        if (this.hitbox.getCenterX() < hitbox.getCenterX()) {
            overX = hitbox.getMaxX() - this.hitbox.getMinX();
        } else {
            overX = hitbox.getMinX() - this.hitbox.getMaxX();
        }

        if (this.hitbox.getCenterY() < hitbox.getCenterY()) {
            overY = hitbox.getMaxY() - this.hitbox.getMinY();
        } else {
            overY = hitbox.getMinY() - this.hitbox.getMaxY();
        }
    
        x -= overX;
        y -= overY;
    }

I would like to know if there is a better way to solve the overlap issue without the enemies continuously pushing each other.


Solution

  • Welp, I ended up with this:

    double angle = Math.atan2(playerY - y, playerX - x);
        double deltaX = Math.cos(angle) * speed/fps;
        double deltaY = Math.sin(angle) * speed/fps;
        Rectangle2D deltaHitbox = new Rectangle2D.Double(x+deltaX, y+deltaY, 40, 40);
        Iterator<Enemies> iterator = enemiesList.iterator();
        while (iterator.hasNext()) {
            Enemies enemy = iterator.next();
            if (enemy == this)continue;
            if (enemy.hitbox.intersects(deltaHitbox)) {
                double deltaXCenter = -deltaHitbox.getCenterX() + enemy.hitbox.getCenterX();
                double deltaYCenter = -deltaHitbox.getCenterY() + enemy.hitbox.getCenterY();
                int separation = 40;
                if (Math.abs(deltaXCenter) > Math.abs(deltaYCenter)) {
                    if (deltaXCenter > 0) {
                        x += (deltaXCenter - separation);
                    } else {
                        x -= (Math.abs(deltaXCenter) - separation);
                    }
                } else {
                    if (deltaYCenter > 0) {
                        y += (deltaYCenter - separation);
                    } else {
                        y -= (Math.abs(deltaYCenter) - separation);
                    }
                }
            }
        }
        x += deltaX;
        y += deltaY;
        hitbox.setFrame(x, y, 40, 40);
    

    so I simply calculate the difference between the centers when moving it hypothetically, and subtract the difference between them, so when it is added, it will always be at a distance which when adding the normal movement, it will not reach the other, and that works even when there is more than one (I do not know if I could explain the idea well).