【问题标题】:Collection of StackPanes collision detectionStackPanes 碰撞检测集合
【发布时间】:2022-09-07 18:11:23
【问题描述】:

我有一组形状,我试图检查彼此之间的碰撞,但到目前为止,我所做的只是检测彼此最接近的三个节点之间的碰撞。

addToRectCollection 方法将堆栈窗格添加到集合中,onDragged 男性每个形状都可拖动。

我应该更改/添加什么来检测集合中所有元素之间的冲突?

下面是我的代码:

public class CollisionDection extends Application {
    final ObjectProperty<Point2D> mousePosition = new SimpleObjectProperty<>();
    Group gp = new Group();

    *I try to detect collisions between elements of this list*
    ArrayList<StackPane> stackPanes = new ArrayList<>();

    @Override
    public void start(Stage stage) throws Exception {

        Scene sc = new Scene(gp, 700, 300);

        Button btn = new Button();
        btn.setText(\"CREATE REct\");

        btn.setOnAction(event -> {
            Rectangle r = createRect(0);
            r.setFill(Color.RED);

            Text text = new Text(\".\");
            StackPane stack = new StackPane();

            StackPane.setMargin(r, new Insets(8, 8, 8, 8));
            stack.getChildren().addAll(r, text);

            ChoiceBox<String> dropdown = new ChoiceBox<>();
            stack.getChildren().add(dropdown);

            makeDraggable(stack);
            addToRectCollection(stack);

            gp.getChildren().add(stack);
        });

        gp.getChildren().add(btn);

        stage.setScene(sc);
        stage.show();
    }

    private void addToRectCollection(StackPane r) {
        stackPanes.add(r);
        stackPanes.forEach(rect -> {
            stackPanes.forEach(rect2 -> {
                if (!rect.equals(rect2)) {
                    setOnDragegd(rect2, rect);
                    setOnDragegd(rect, rect2);
                }
            });
        });
    }

    private void setOnDragegd(StackPane pane, StackPane paneToSetDragged) {
        paneToSetDragged.setOnMouseDragged((MouseEvent event) -> {
            double deltaX = event.getSceneX() - mousePosition.get().getX();
            double deltaY = event.getSceneY() - mousePosition.get().getY();
            paneToSetDragged.setLayoutX(paneToSetDragged.getLayoutX() + deltaX);
            paneToSetDragged.setLayoutY(paneToSetDragged.getLayoutY() + deltaY);
            mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY()));

            var intersect = paneToSetDragged.getBoundsInParent().intersects(pane.getBoundsInParent());
            if (intersect) {

                pane.setStyle(\"-fx-background-color: #6a5246\");
                paneToSetDragged.setStyle(\"-fx-background-color: #6a5246\");

                Group g = new Group();
                g.getChildren().add(paneToSetDragged);
                g.getChildren().add(pane);
                gp.getChildren().add(g);

                paneToSetDragged.setLayoutX(paneToSetDragged.getLayoutX() - deltaX);
                paneToSetDragged.setLayoutY(paneToSetDragged.getLayoutY() - deltaY);
            } else {
                pane.setStyle(\"-fx-background-color: #ffffff\");
                paneToSetDragged.setStyle(\"-fx-background-color: #ffffff\");
            }
        });
    }

    private void makeDraggable(StackPane ractangleToSetDragged) {
        ractangleToSetDragged.setOnMousePressed((MouseEvent event) -> mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY())));

        ractangleToSetDragged.setOnMouseDragged((MouseEvent event) -> {
            double deltaX = event.getSceneX() - mousePosition.get().getX();
            double deltaY = event.getSceneY() - mousePosition.get().getY();
            ractangleToSetDragged.setLayoutX(ractangleToSetDragged.getLayoutX() + deltaX);
            ractangleToSetDragged.setLayoutY(ractangleToSetDragged.getLayoutY() + deltaY);
            mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY()));
        });
    }

    public Rectangle createRect(int x) {
        Rectangle r = new Rectangle();
        r.setX(x);
        r.setY(60);
        r.setWidth(300);
        r.setHeight(150);

        return r;
    }

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

    标签: java javafx


    【解决方案1】:

    您需要测试与全部StackPane.onMouseDragged 的处理程序中的其他窗格,用于添加到集合中的每个窗格。

    您现在所做的事情是不正确的,因为您每次添加新的 StackPane 时都会为每个窗格重新设置处理程序。这可能使用StackPane.addEventHandler(MouseEvent.MOUSE_DRAGGED, ...) 而不是StackPane.setOnMouseDragged(...) 起作用,但它会很重、很慢并且会消耗内存,因为它可能会为每个新的 StackPane 链接大量事件处理程序。

    由于您一次只有一个移动窗格(当它被拖动时),您宁愿为每个新窗格设置一次 onMouseDragged 处理程序,然后在此处理程序中循环遍历您的 stackPanes ArrayList 以测试与所有其他窗格的交集,这会将您的代码更改为如下所示:

    private void addToRectCollection(StackPane r) {
      stackPanes.add(r);
      r.setOnMouseDragged((MouseEvent event) -> {
        double deltaX = event.getSceneX() - mousePosition.get().getX();
        double deltaY = event.getSceneY() - mousePosition.get().getY();
        r.setLayoutX(r.getLayoutX() + deltaX);
        r.setLayoutY(r.getLayoutY() + deltaY);
        mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY()));
        //Test collision for this pane with all other ones
        testCollision(r);
      });
    }
    
    private void testCollision(StackPane r) {
      //Loop through all stackPanes
      for (StackPane r2 : stackPanes) {
        if (r2 == r) //except r
          continue;
        //test intersection with r
        var intersect = r.getBoundsInParent().intersects(r2.getBoundsInParent());
        if (intersect) {
          //Style intersecting pane
          r2.setStyle("-fx-background-color: #6a5246");
          r.setStyle("-fx-background-color: #6a5246");
    
          Group g = new Group();
          g.getChildren().add(r);
          g.getChildren().add(r2);
          gp.getChildren().add(g);
    
          r.setLayoutX(r.getLayoutX() - deltaX);
          r.setLayoutY(r.getLayoutY() - deltaY);
        } else {
          //Unstyle
          r2.setStyle("-fx-background-color: #ffffff");
          r.setStyle("-fx-background-color: #ffffff");
        }
      }
    }
    

    (我已经摆脱了setOnDragegd 方法,它只会设置onMouseDragged 处理程序并定义了一个专门用于评估与被拖动窗格的碰撞的testCollision 方法)

    但是,您仍然会遇到样式问题,因为每当您检测到一次碰撞时,您都会重新执行它,而任何窗格都可能随时与其他几个窗格相交... 这可以通过两种明显的方式解决:

    1. 记住已知的交叉点,并在拖动窗格时更新它们,然后评估哪些窗格应该着色
    2. 通过评估每个窗格与stackPanes arrayList 之前的每个其他窗格,而不是我在此处提供的简单循环,重新测试每个事件的每个可能的冲突。(仅适用于少量窗格)

      但这可能是另一个问题......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-05
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多