我在试着重现越狱游戏。球反弹并检测到碰撞。然而,同时发生了太多的冲突。球一次可以毁掉不止一块砖。
我从一个圆圈作为球开始,但后来将它改为矩形,以帮助获得更精确的碰撞检测。但这并不能完全解决问题。
当检测到碰撞时,我尝试反转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);
}
}发布于 2021-07-09 03:55:01
我添加了一些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);
}
}https://stackoverflow.com/questions/68278968
复制相似问题