简体   繁体   中英

Java collision swing not working from the sides

I'm doing a java game like breaking bricks. I have already collision detection. But now I want to destroy some blocs if their HP is equals to 0. If i touch my bloc below or above, it works fine, each ball takes 1 HP to the bloc. But if i touch the bloc from left or right, the bloc is destroyed, despite having HP left.

Each time I touch a bloc, I check the position of my ball compared to the bloc. But for the right and left I don't understand why it's not working.

I'm also not sure about the way I destroy the blocs.. I mean, I store all the blocs in a Map. I get the current wave of my bloc ( the line so). And then I compare the bloc given in parameter to all the blocs of that line. Is that right ?

for (Ball ball : ballList) {
            for (List<Bloc> wave : mapBlocs.values()) {
                for (Bloc bloc : wave) {
                    if (ball.getBounds().intersects(bloc.getBounds())) {
                        if (ball.getPosY() <= bloc.getPosY() + bloc.getHeight()) {
                            ball.setVelocityY(-ball.getVelocityY());
                            ball.setPosY(ball.getPosY() + ball.getVelocityY());
                            bloc.setHardness(bloc.getHardness() - 1);
                            System.out.println("below");
                        } else if (ball.getPosY() + ball.getHeight() >= bloc.getPosY()) {
                            ball.setVelocityY(-ball.getVelocityY());
                            ball.setPosY(ball.getPosY() + ball.getVelocityY());
                            bloc.setHardness(bloc.getHardness() - 1);
                            System.out.println("above");

                        } else if (ball.getPosX() + ball.getWidth() <= bloc.getPosX()) {
                            ball.setVelocityX(-ball.getVelocityX());
                            ball.setPosX(ball.getPosX() + ball.getVelocityX());
                            bloc.setHardness(bloc.getHardness() - 1);
                            System.out.println(bloc.getHardness());
                            System.out.println("left");

                        } else if (ball.getPosX() >= bloc.getPosX() + bloc.getWidth()) {
                            ball.setVelocityX(-ball.getVelocityX());
                            ball.setPosX(ball.getPosX() + ball.getVelocityX());
                            bloc.setHardness(bloc.getHardness() - 1);
                            System.out.println(bloc.getHardness());
                            System.out.println("right");
                        }
                        if (bloc.getHardness() == 0) {
                            destroyBlocs(bloc);
                    }


                    }
                }

And my method destroyBlocs:

    private void destroyBlocs(Bloc bloc) {

        List<Bloc> list = mapBlocs.get(bloc.getWaveNumber());
        for (Bloc a : list) {
            if (a.equals(bloc)) {
                list.remove(bloc);
            }
        }

    }

How can I fix ? And thank you in advance !

@UPDATE

When I test my app, when I hit a bloc from the sides, the ball does a different action. It goes through the bloc, so it counts an infinity of hits, so I think that's why the bloc instantly disappears, so my question is : why I dont get the rebound when I hit the bloc from the sides ?

Hmm, I had another look at your code and I might have spotted the error (debugging should confirm this): your conditions seem to check whether the ball is outside the block.

Assuming that Ball and Bloc are swing components the coordinate 0/0 would mean the top left corner and thus positive y is down.

Thus a block's edges could partly defined as

  • top: block.y
  • bottom: block.y + block.height
  • left: block.x
  • right: block.x + block.width

Now let's visualize your conditions which only apply if the ball's and block's boundaries intersect:

  1. "below": ball.y <= block.y + bloc.height
  2. "above": ball.y + ball.height >= block.y
  3. "left": ball.x + ball.width <= block.x
  4. "right": ball.x >= block.x + block.width

For simplicity we'll assume the ball is just a dot, ie the with and height are 1. We'll thus ignore the ball's size and just use its position (which represents the ball's pixel anyways) and simplify your equations (which might be off by 1 btw):

  1. "below": ball.y <= block.y + bloc.height
  2. "above": ball.y >= block.y
  3. "left": ball.x <= block.x
  4. "right": ball.x >= block.x + block.height

Now let's visualize those with some arrows to indicate where they would be true:

   +----------+  ---
   |          |   | (2)
   |  Block   |   V        ^
   |          |            | (1)
   +----------+           ---

<--|          |-->
 (3)           (4)

The main problem now is that you're checking those conditions in order. What happens if the ball hits the block from the side? Condition 1 will most likely already be true and you'd just change the y-condition. If it still is inside the block either condition 1 or 2 would still be true and you'd change the y-condition back.

However, there's also a problem with the conditions 3 and 4:

Due to the check for the intersection your original condition 3 could only be true if the ball is right at the left edge which might not be a hit at all. If it is a little more to the right the condition wouldn't be true anymore.

Let's do an example with a ball of width 5 and a block with x-position 10. Your condition ball.x + ball.width <= block.x would thus be ball.x + 5 <= 10 . This could only be true for ball.x <= 5. However, for any ball.x < 5 you'd get a right boundary of 9 or less for the ball which means the it doesn't interesect the block.

Condition 4 is similar: let's assume the block has a width of 20 and a x-position of 10. Thus ball.x >= block.x + block.width becomes ball.x >= 30 (10 + 20). That means it would only be true if the ball has an x-position of exactly 30 but that wouldn't mean an intersection.

After checking @Thomas explanation , I got this solution :

                    if (ball.getVelocityX() > 0) {
                        if (ball.getPosX() < bloc.getPosX()) {
                            ball.setVelocityX(-ball.getVelocityX());
                            ball.setPosX(ball.getPosX() + ball.getVelocityX());
                            bloc.setHardness(bloc.getHardness() - 1);
                            // left hit
                        } else {
                            ball.setVelocityY(-ball.getVelocityY());
                            ball.setPosY(ball.getPosY() + ball.getVelocityY());
                            bloc.setHardness(bloc.getHardness() - 1);
                            // below hit
                        }
                    } else {
                        if (ball.getPosX() < bloc.getPosX() + bloc.getWidth()) {
                            ball.setVelocityY(-ball.getVelocityY());
                            ball.setPosY(ball.getPosY() + ball.getVelocityY());
                            bloc.setHardness(bloc.getHardness() - 1);
                            // above hit
                        } else {
                            ball.setVelocityX(-ball.getVelocityX());
                            ball.setPosX(ball.getPosX() + ball.getVelocityX());
                            bloc.setHardness(bloc.getHardness() - 1);
                            // right hit
                        }
                    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM