JavaFX 中 ImageView 的交集

Intersect of ImageView's in JavaFX

为什么这些语句不起作用?

if (iv_ship.intersects(iv_plane.getBoundsInLocal())) System.out.println("xxxxxxxxx");
if (iv_plane.intersects(iv_ship.getBoundsInLocal())) System.out.println("zzzz");
if (iv_plane.getBoundsInLocal().intersects(iv_ship.getBoundsInLocal())) System.out.println("dupa");

我很确定这两个对象相交。也许是 TranslateTransition 的错? 但我也试图在海岸上与不是 TT 的矩形相交。 最好的问候。

这是全部代码:

package riverpuff.v3;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import javafx.animation.AnimationTimer;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 *
 * @author Marek
 */
public class RiverPuffV3 extends Application {

    public String name = "";
    public Rectangle shot = new Rectangle();

    @Override
    public void start(Stage primaryStage) {

        createMenu(primaryStage);

        primaryStage.show();
        primaryStage.setResizable(false);
        primaryStage.getIcons().
                add(new Image(getClass().getResourceAsStream("Icon.png")));
    }

    private void createMenu(Stage primaryStage) {

        primaryStage.setScene(null);

        GridPane pane_menu = new GridPane();

        Button button_name = new Button("Name");
        button_name.setMaxHeight(Double.MAX_VALUE);
        button_name.setMaxWidth(Double.MAX_VALUE);
        button_name.setOnAction(e -> {
            createName(primaryStage);
            /*try{        
                OutputStreamWriter writer = new OutputStreamWriter( new FileOutputStream("log.txt", true), "UTF-8");
                BufferedWriter fbw = new BufferedWriter(writer);
                fbw.newLine();
                fbw.write("append txt...");
                fbw.newLine();
                fbw.close();
            }
            catch (Exception v) {
            System.out.println("Error: " + v.getMessage());
            }*/
        });

        Button button_start = new Button("Start");
        button_start.setMaxHeight(Double.MAX_VALUE);
        button_start.setMaxWidth(Double.MAX_VALUE);
        button_start.setOnAction(e -> {
            drawGame(primaryStage);
        });

        pane_menu.setHgap(10);
        pane_menu.setVgap(10);
        pane_menu.add(button_name,0,10,10,10);
        pane_menu.add(button_start,15,10,10,10);

                                                                                //reading name from a file
        try {
            String read_file = null;
            BufferedReader in = new BufferedReader(new FileReader("log.txt"));
            read_file = in.readLine();
            Text text_name = new Text("Hello " + read_file);
            pane_menu.add(text_name,5,5,10,5);
        } catch (FileNotFoundException e) {
            System.out.println("File not found!");
            //throw new RuntimeException("File not found");
        } catch (IOException e) {
            System.out.println("IO Error occured");
            //throw new RuntimeException("IO Error occured");
        } 

        Scene scene_menu = new Scene(pane_menu, 300, 500);

        primaryStage.setTitle("River Puff");
        primaryStage.setScene(scene_menu);

    }

                                                                                //save name to a file
    private void createName (Stage primaryStage) {

        primaryStage.setScene(null);

        GridPane pane_name = new GridPane();

        TextField tf_name = new TextField();
        tf_name.setMaxHeight(50);
        tf_name.setMaxWidth(240);
        tf_name.setAlignment(Pos.CENTER);
        tf_name.setFont(Font.font("Verdana",25));
        tf_name.setOnKeyPressed(ke -> {
            if (ke.getCode() == KeyCode.ENTER) {
                name = tf_name.getText();
                if (!name.isEmpty()){
                    MyFile myFile = new MyFile();
                    myFile.writeTextFile("log.txt", name);
                }
                createMenu(primaryStage);
            }
        });
        Button button_ok = new Button("OK");        
        button_ok.setMaxHeight(30);
        button_ok.setMaxWidth(80);
        button_ok.setOnAction(e -> {
            name = tf_name.getText();
            if (!name.isEmpty()){
                MyFile myFile = new MyFile();
                myFile.writeTextFile("log.txt", name);
            }
            createMenu(primaryStage);
        });

        Text text_name = new Text("What is your name?");
        text_name.setFont(Font.font("Verdana",15));

        pane_name.setHgap(10);
        pane_name.setVgap(10);

        pane_name.add(text_name,8,9,5,5);
        pane_name.add(button_ok,11,22,8,3);
        pane_name.add(tf_name,3,15,24,5);

        Scene scene_name = new Scene(pane_name, 300, 500);

        primaryStage.setTitle("River Puff - Name");
        primaryStage.setScene(scene_name);

    }

    private void drawGame (Stage primaryStage) {

        primaryStage.setScene(null);

        final int H = 700;
        final int W = 1000;

        Group root = new Group();
        Scene scene_game = new Scene(root, W, H, Color.LIGHTBLUE);

        Button button_menu = new Button("Menu");
        button_menu.setOnAction(e ->{
            createMenu(primaryStage);
        });

        Image ship = new Image((getClass().getResourceAsStream("ship.png")));   //loading images
        Image plane = new Image((getClass().getResourceAsStream("Icon.png")));

        /**********************************************************************/

        Rectangle[] coastL = {
            new Rectangle(), new Rectangle(),
            new Rectangle(), new Rectangle(), 
            new Rectangle(), new Rectangle(), 
            new Rectangle(), new Rectangle()
        }; 
        Rectangle[] coastR = {            
            new Rectangle(), new Rectangle(),
            new Rectangle(), new Rectangle(), 
            new Rectangle(), new Rectangle(), 
            new Rectangle(), new Rectangle()
        };


        for (int i=0; i<8; i++) {
            coastL[i].setFill(Color.FORESTGREEN);
            coastL[i].setHeight(100);
            coastR[i].setFill(Color.FORESTGREEN);
            coastR[i].setHeight(100);
        }


        AnimationTimer timer = new AnimationTimer() {
            int[] j = {0,0,0,0,0,0,0,0};

            @Override
            public void handle(long now) {

                for (int i=0; i<8; i++) if (j[i]==(i*100+800)) j[i]=i*100;

                for (int i=1;i<9;i++) {                                         //creating coast
                    coastL[i-1].setX(0);
                    coastL[i-1].setY(j[i-1]-(i*100));
                    coastL[i-1].setWidth(250+i*(i%3));

                    coastR[i-1].setX(W-(250+i*(i%4)));
                    coastR[i-1].setY(j[i-1]-(i*100));
                    coastR[i-1].setWidth(250+i*(i%4));
                } 
                for (int i=0;i<8;i++) j[i]++;
            }
        };
        timer.start();

        ImageView iv_ship = new ImageView();
        iv_ship.setImage(ship);
        iv_ship.setFitWidth(150);
        iv_ship.setFitHeight(45);
        iv_ship.setX(300);
        iv_ship.setY(0);

        TranslateTransition tt_shipX = 
                new TranslateTransition(Duration.millis(2000), iv_ship);        //moving enemies
        tt_shipX.setAutoReverse(true);
        tt_shipX.setCycleCount(Timeline.INDEFINITE);        
        tt_shipX.setByX(200f);
        tt_shipX.play();    

        TranslateTransition tt_shipY = 
                new TranslateTransition(Duration.millis(13000), iv_ship);
        tt_shipY.setAutoReverse(false);
        tt_shipY.setCycleCount(Timeline.INDEFINITE);
        tt_shipY.setByY(800);
        tt_shipY.play();        

        ImageView iv_plane = new ImageView();
        iv_plane.setImage(plane);
        iv_plane.setFitWidth(50);
        iv_plane.setFitHeight(50);
        iv_plane.setX(475);
        iv_plane.setY(600);

        TranslateTransition tt_plane = 
                new TranslateTransition(Duration.millis(1), iv_plane);          

        TranslateTransition tt_shot = 
                new TranslateTransition(Duration.millis(4000), shot);
        tt_shot.setAutoReverse(false);
        tt_shot.setCycleCount(1);
        TranslateTransition tt_shotB =
                new TranslateTransition(Duration.millis(0.5f), shot);
        tt_shotB.setAutoReverse(false);
        tt_shotB.setCycleCount(1);

        root.setOnKeyPressed((KeyEvent ke) -> {                                 //steering a plane            }
            if (ke.getCode() == KeyCode.LEFT && 
                    tt_plane.getNode().getTranslateX() > -475) {
                tt_plane.setByX(-5f);
                tt_plane.play();
                System.out.println(tt_plane.getNode().getTranslateX());
            }
            else if (ke.getCode() == KeyCode.RIGHT && 
                    tt_plane.getNode().getTranslateX() < 475) {
                tt_plane.setByX(5f);
                tt_plane.play();
                System.out.println(tt_plane.getNode().getTranslateX());
            }
            else if (ke.getCode() == KeyCode.A) {
                shot.setFill(Color.BLACK);
                shot.setX(tt_plane.getNode().getTranslateX()+495);
                shot.setY(580);
                shot.setWidth(10);
                shot.setHeight(20);

                tt_shot.setByY(-600);
                tt_shot.play();
                tt_shot.setOnFinished((ActionEvent arg0) -> {
                    shot.setDisable(true);
                    tt_shotB.setByY(600);
                    tt_shotB.play();
                });
            }
        });

        if (iv_ship.intersects(iv_plane.getBoundsInLocal())) System.out.println("xxxxxxxxx");
        if (iv_plane.intersects(iv_ship.getBoundsInLocal())) System.out.println("zzzz");
        if (iv_plane.getBoundsInLocal().intersects(iv_ship.getBoundsInLocal())) System.out.println("dupa");

        root.getChildren().add(button_menu);
        for (int i=0; i<8; i++) {
            root.getChildren().add(coastL[i]);
            root.getChildren().add(coastR[i]);
        }
        root.getChildren().add(iv_plane);
        root.getChildren().add(iv_ship);
        root.getChildren().add(shot);
        primaryStage.setScene(scene_game);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

首先,您需要考虑到节点可以转换(通过翻译),因此您需要 getBoundsInParent().

而不是 getBoundsInLocal()

根据 javadocs:

getBoundsInParent() gets the value of the property boundsInParent. The rectangular bounds of this Node which include its transforms. boundsInParent is calculated by taking the local bounds (defined by boundsInLocal) and applying the transform created.

这将在两个节点的任何给定位置起作用:

if(iv_plane.getBoundsInParent().intersects(iv_ship.getBoundsInParent())){
    System.out.println("Intersection detected");
}

下一个你要解决的问题是你什么时候检查可能的路口。根据您的代码,您只检查了一次,当时节点甚至没有添加到 root/scene/stage。那是行不通的。

为此,您必须在每次移动其中一个时进行检查,使用一些侦听器来监听 translateXProperty()translateYProperty() 中的变化,如下所示:

private final ChangeListener<Number> checkIntersection = (ob,n,n1)->{
    if (iv_plane.getBoundsInParent().intersects(iv_ship.getBoundsInParent())){
        System.out.println("Intersection detected");
    }
};

private ImageView iv_ship, iv_plane;

private void drawGame (Stage primaryStage) {
    iv_ship = new ImageView();
    iv_plane = new ImageView();
    ...
    iv_ship.translateXProperty().addListener(checkIntersection);
    iv_ship.translateYProperty().addListener(checkIntersection);
    ...
    root.getChildren().addAll(iv_plane,iv_ship);
    primaryStage.setScene(scene_game);
}