使用javafx的突破游戏冲突太多

uubf1zoe  于 2021-08-25  发布在  Java
关注(0)|答案(1)|浏览(271)

我正在尝试重新创建突破游戏。球反弹并检测到碰撞。然而,太多的碰撞同时发生。这个球一次破坏一块以上的砖块。
我开始用一个圆作为球,但后来把它改成了一个矩形,以帮助获得更准确的碰撞检测。但这并不能完全解决问题。
我已尝试在检测到碰撞时反转y坐标。因此,一旦物体发生碰撞,球就会回到球拍上。但这并不能完全解决问题。我想避免背对背的冲突。我看过类似的帖子,但对我没有帮助。有什么建议吗?

package breakoutgame;

import javafx.application.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.stage.Stage;
import javafx.animation.*;
import javafx.event.*;
import javafx.util.Duration;
import java.util.*;
import javafx.scene.control.Label;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.text.Font;

public class BreakoutGame extends Application {

    @Override
    public void start(Stage window) {
        //creates main layout

        Pane layout= new Pane();
        layout.setStyle("-fx-background-color: black");
        layout.setPrefSize(610,400); 

        Scene view= new Scene(layout);

        //creates components and adds them to the main layout

        ArrayList<Rectangle> allBricks = new ArrayList<>();
        for(int x=0; x<10; x++) {
            for(int y=0; y<8; y++) {
                Rectangle brick=new Rectangle(60,15);
                if(y<=1){
                    brick.setFill(Color.RED);
                }
                if(y>1 && y<=3){
                    brick.setFill(Color.ORANGE);
                }
                if(y>3 && y<=5){
                    brick.setFill(Color.GREEN);
                }
                if(y>5 && y<8){
                    brick.setFill(Color.YELLOW);
                }
                brick.setLayoutX(x*62);
                brick.setLayoutY((16*y)+35);
                layout.getChildren().add(brick);
                allBricks.add(brick);
            }
        }
        Rectangle ball= new Rectangle(20,20, Color.BLUE);
        ball.relocate(300, 200);

        Rectangle paddle= new Rectangle(90,7, Color.ORANGERED);
        paddle.relocate(275, 390);

        layout.getChildren().addAll(paddle, ball);

        //controls paddle movement

       int movement = 15;

        view.setOnKeyPressed(event -> {
            if (event.getCode() == KeyCode.LEFT) {
                if(paddle.getLayoutX() < 0) {
                     paddle.setLayoutX(paddle.getLayoutX()+movement);
                }
                paddle.setLayoutX(paddle.getLayoutX()-movement);
            }

            if (event.getCode() == KeyCode.RIGHT) {
                if(paddle.getLayoutX() > 510) {
                     paddle.setLayoutX(510);
                } 
                paddle.setLayoutX(paddle.getLayoutX()+movement);
            }
         });

        //creates an indefinite bouncing ball

        Timeline timeline = new Timeline(new 
        KeyFrame(Duration.millis(20), 
            new EventHandler<ActionEvent>() {

            double dx = 5; 
            double dy = 3; 

           @Override
            public void handle(ActionEvent t) {
                //ball movement
                ball.setLayoutX(ball.getLayoutX() + dx);
                ball.setLayoutY(ball.getLayoutY() + dy);

                boolean leftWall = ball.getLayoutX() <= 0; 
                boolean topWall = ball.getLayoutY() < 35;
                boolean rightWall = ball.getLayoutX() >= 590;
                boolean bottomWall = ball.getLayoutY() >= 380;

                // If the top wall has been touched, the ball reverses direction.
                if (topWall) {
                   dy = dy * -1;
                }

                // If the left or right wall has been touched, the ball reverses direction.
                if (leftWall || rightWall) {
                    dx = dx * -1;
                }
                if(bottomWall) {
                    dy = dy * -1;
                }

                //if ball collides with paddle
                if (collide(paddle)) {
                dy = -dy;
                }

                //if ball and brick collides, remove brick

                Rectangle temp=null;
                for(Rectangle brick:allBricks) { 
                    if(collide(brick)) {
                        temp=brick;
                        layout.getChildren().remove(brick);
                        dy=-dy;
                    }
                }
                allBricks.remove(temp);
                temp=null;
            }
            public boolean collide(Rectangle other) {
                Shape collisionArea = Shape.intersect(ball, other);
                return collisionArea.getBoundsInLocal().getWidth() != -1;
            }
        }));

        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();

        window.setTitle("Breakout Game!");
        window.setScene(view);
        window.show();

    }

    public static void main(String[] args) {
        launch(args);
    }

}
uxh89sit

uxh89sit1#

我添加了一些system.out.println()调用,以查看球何时移动以及砖块何时被击中。我没有看到任何来自同一个动作的双重打击,但我确实看到它有时在从另一块砖块反弹后击中第二块砖块。
我做了一些其他的重构,只是为了让我更容易了解它的工作原理,所以这就是你在这里得到的:

public class BreakoutGame extends Application {

    @Override
    public void start(Stage window) {
        Pane layout = new Pane();
        layout.setStyle("-fx-background-color: black");
        layout.setPrefSize(610, 400);
        Scene view = new Scene(layout);
        layout.getChildren()
              .addAll(IntStream.range(0, 10)
                               .boxed()
                               .flatMap(x -> IntStream.range(0, 8).mapToObj(y -> createBrick(x, y)))
                               .collect(Collectors.toList()));
        Rectangle ball = new Rectangle(20, 20, Color.BLUE);
        ball.relocate(300, 200);
        Rectangle paddle = new Rectangle(90, 7, Color.ORANGERED);
        paddle.relocate(275, 390);

        layout.getChildren().addAll(paddle, ball);

        int movement = 15;

        view.setOnKeyPressed(event -> {
            if (event.getCode() == KeyCode.LEFT) {
                paddle.setLayoutX(paddle.getLayoutX() - movement * ((paddle.getLayoutX() < 0) ? -1 : 1));
            }
            if (event.getCode() == KeyCode.RIGHT) {
                paddle.setLayoutX((paddle.getLayoutX() > 510) ? 510 : (paddle.getLayoutX() + movement));
            }
        });

        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(20), new EventHandler<ActionEvent>() {

            double dx = 5;
            double dy = 3;

            @Override
            public void handle(ActionEvent t) {
                ball.setLayoutX(ball.getLayoutX() + dx);
                ball.setLayoutY(ball.getLayoutY() + dy);
                if (ball.getLayoutY() < 35 || collide(paddle)) {
                    dy = dy * -1;
                }
                if (ball.getLayoutX() <= 0 || ball.getLayoutX() >= 590) {
                    dx = dx * -1;
                }
                if (ball.getLayoutY() >= 380) {
                    dy = dy * -1;
                }
                System.out.println("Move: [" + ball.getLayoutX() + ", " + ball.getLayoutY() + "]");
                layout.getChildren()
                      .stream()
                      .filter(child -> (child != paddle) && (child != ball))
                      .filter(brick -> collide((Rectangle) brick))
                      .findFirst()
                      .ifPresent(brick -> {
                          System.out.println("******************-> Collide " + brick.getId());
                          layout.getChildren().remove(brick);
                          dy = -dy;
                      });
            }

            public boolean collide(Rectangle other) {
                return Shape.intersect(ball, other).getBoundsInLocal().getWidth() != -1;
            }
        }));

        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();

        window.setTitle("Breakout Game!");
        window.setScene(view);
        window.show();

    }

    @NotNull
    private Rectangle createBrick(int x, int y) {
        Rectangle brick = new Rectangle(60, 15);
        brick.setFill(switch (y) {
            case 0, 1 -> Color.RED;
            case 2, 3 -> Color.ORANGE;
            case 4, 5 -> Color.GREEN;
            default -> Color.YELLOW;
        });
        brick.setLayoutX(x * 62);
        brick.setLayoutY((16 * y) + 35);
        brick.setId("[" + x + ", " + y + "]");
        return brick;
    }

    public static void main(String[] args) {
        launch(args);
    }

}

相关问题