我在做克朗代克游戏。逻辑全部正常。我在用javafx中的UI遇到麻烦。

我一直在尝试将卡从“桌面堆”区域移动/拖动,但没有得到预期的结果。
我的卡是一个ImageView,里面有一个Image。卡位于窗格中:

Pane tableau = new Pane();
for (int i = 0; i < n; i++) {
    Image img = new Image("resources/images/" + (i + 1) + ".png");
    ImageView imgView = new ImageView(img);
    imgView.setY(i * 20);
    //imgView Mouse Events here
    tableau.getChildren().add(imgView);
}


我试过了:

imgView.setOnMousePressed((MouseEvent mouseEvent) -> {
    dragDelta.x = imgView.getLayoutX() - mouseEvent.getSceneX();
    dragDelta.y = imgView.getLayoutY() - mouseEvent.getSceneY();
});
imgView.setOnMouseDragged((MouseEvent mouseEvent) -> {
    imgView.setLayoutX(mouseEvent.getSceneX() + dragDelta.x);
    imgView.setLayoutY(mouseEvent.getSceneY() + dragDelta.y);
});


该解决方案无法正常工作,因为我正在设置位置,因此放开卡时不会回到原来的位置,并且卡正在与其他UI对象发生碰撞。

另一尝试:

imgView.setOnDragDetected((MouseEvent event) -> {
    ClipboardContent content = new ClipboardContent();
    content.putImage(img);
    Dragboard db = imgView.startDragAndDrop(TransferMode.ANY);
    db.setDragView(img, 35, 50);
    db.setContent(content);
    event.consume();
});


在此解决方案中,问题是:卡变成半透明的,就像移动文件一样,光标变为否/禁止,但是除此之外,它工作得很好:如果我释放鼠标,则不会发生碰撞并且卡会回到其原始位置。
另一个问题是我不知道我是否可以使用此解决方案移动一张以上的卡?

我的最后一个问题是,如何像纸牌游戏中那样将一个节点(在本例中为ImageView)或一组节点从一个堆移动到另一个堆?

最佳答案

为了知道原始卡的位置,应在鼠标处理程序中使用setTranslateX(和Y)而不是setLayoutX。因此,当用户释放卡片时,您可以简单地调用过渡,让卡片飞回布局位置。如果用户在有效的地方释放卡,则将平移坐标设置为0并更改布局位置或使用relocate

如果要使卡片半透明,可以e。 G。更改opacity或应用CSS。

顺便说一句,我不会使用Clipboardcontent,这似乎不适合您的需求。

您可以使用鼠标处理代码移动多个对象。您只需将转换同时应用于多个对象即可。拖动桩时,您将确定选定牌上方的牌,并将过渡应用于所有牌。



这是一个简单的示例,向您展示它的外观。

Card.java,您将使用ImageView。

public class Card extends Rectangle {

    static Random rand = new Random();

    public Card() {


        setWidth(100);
        setHeight(200);

        Color color = createRandomColor();

        setStroke(color);
        setFill( color.deriveColor(1, 1, 1, 0.4));

    }

    public static Color createRandomColor() {

        int max = 200;

        Color color = Color.rgb( (int) (rand.nextDouble() * max), (int) (rand.nextDouble() * max), (int) (rand.nextDouble() * max));

        return color;
    }
}


Game.java,应用程序。

public class Game extends Application {

    static List<Card> cardList = new ArrayList<>();

    @Override
    public void start(Stage primaryStage) {

        MouseGestures mg = new MouseGestures();

        Group root = new Group();

        for( int i=0; i < 10; i++) {

            Card card = new Card();
            card.relocate( i * 20, i * 10);

            mg.makeDraggable(card);

            cardList.add( card);
        }

        root.getChildren().addAll( cardList);

        Scene scene = new Scene( root, 1600, 900);

        primaryStage.setScene( scene);
        primaryStage.show();

    }

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

    // TODO: don't use a static method, I only added for the example
    public static List<Card> getSelectedCards( Card currentCard) {

        List<Card> selectedCards = new ArrayList<>();

        int i = cardList.indexOf(currentCard);
        for( int j=i + 1; j < cardList.size(); j++) {
            selectedCards.add( cardList.get( j));
        }

        return selectedCards;
    }

}


MouseGestures.java,鼠标处理机制。

public class MouseGestures {

    final DragContext dragContext = new DragContext();

    public void makeDraggable(final Node node) {

        node.setOnMousePressed(onMousePressedEventHandler);
        node.setOnMouseDragged(onMouseDraggedEventHandler);
        node.setOnMouseReleased(onMouseReleasedEventHandler);

    }

    EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {

            dragContext.x = event.getSceneX();
            dragContext.y = event.getSceneY();

        }
    };

    EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {

            Node node = (Node) event.getSource();

            double offsetX = event.getSceneX() - dragContext.x;
            double offsetY = event.getSceneY() - dragContext.y;

            node.setTranslateX(offsetX);
            node.setTranslateY(offsetY);

            // same for the other cards
            List<Card> list = Game.getSelectedCards( (Card) node);
            for( Card card: list) {
                card.setTranslateX(offsetX);
                card.setTranslateY(offsetY);
            }


        }
    };

    EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {

            Node node = (Node) event.getSource();

            moveToSource(node);

            // same for the other cards
            List<Card> list = Game.getSelectedCards( (Card) node);
            for( Card card: list) {
                moveToSource(card);
            }

            // if you find out that the cards are on a valid position, you need to fix it, ie invoke relocate and set the translation to 0
            // fixPosition( node);

        }
    };

    private void moveToSource( Node node) {
        double sourceX = node.getLayoutX() + node.getTranslateX();
        double sourceY = node.getLayoutY() + node.getTranslateY();

        double targetX = node.getLayoutX();
        double targetY = node.getLayoutY();

        Path path = new Path();
        path.getElements().add(new MoveToAbs( node, sourceX, sourceY));
        path.getElements().add(new LineToAbs( node, targetX, targetY));

        PathTransition pathTransition = new PathTransition();
        pathTransition.setDuration(Duration.millis(1000));
        pathTransition.setNode(node);
        pathTransition.setPath(path);
        pathTransition.setCycleCount(1);
        pathTransition.setAutoReverse(true);

        pathTransition.play();
    }

    /**
     * Relocate card to current position and set translate to 0.
     * @param node
     */
    private void fixPosition( Node node) {

        double x = node.getTranslateX();
        double y = node.getTranslateY();

        node.relocate(node.getLayoutX() + x, node.getLayoutY() + y);

        node.setTranslateX(0);
        node.setTranslateY(0);

    }

    class DragContext {

        double x;
        double y;

    }

    // pathtransition works with the center of the node => we need to consider that
    public static class MoveToAbs extends MoveTo {

        public MoveToAbs( Node node, double x, double y) {
            super( x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);

        }

    }

    // pathtransition works with the center of the node => we need to consider that
    public static class LineToAbs extends LineTo {

        public LineToAbs( Node node, double x, double y) {
            super( x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
        }

    }

}


当您选择一张或多张纸牌时,它们将过渡回其原点。

这是我从顶部拖动第三张卡的屏幕截图。



当检查卡是否在有效目的地上时,应调用fixPosition方法。它只是简单地重新定位卡,即。 e。使用平移值计算位置,重新定位节点并将其平移设置为0。

棘手的部分是PathTransition。它从节点中心开始工作,而不是从x / y坐标开始工作。 Here's有关该问题的主题,如果您希望进一步了解,请回答。

10-05 22:47
查看更多