使用PerspectiveTransform的JavaFX Flip节点

GGr*_*rec 2 java javafx flip javafx-2

JavaFX 2.x

我想做的事:

  • 此脚本已转换为Java源代码.我自己尝试过,但有些东西已被弃用(例如PerspectiveTransform#time- 在JavaFX 2.2中找不到)
  • 翻转这样那样的.

    我不想做的事:

  • 使用RotateTransition因为它取决于PerspectiveCamera.由于我会有很多可翻转的瓷砖彼此相邻,因此动画中途的前/后替换效果不会很好.

    到目前为止我所拥有的:

    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.effect.PerspectiveTransform;
    import javafx.scene.effect.PerspectiveTransformBuilder;
    import javafx.scene.image.ImageView;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    /**
     * 
     * @author ggrec
     *
     */
    public class FX_Tester extends Application 
    {
    
        @Override
        public void start(final Stage stage) throws Exception 
        {
            final StackPane stackPane = new StackPane();
    
            final ImageView img1 = new ImageView("http://img3.wikia.nocookie.net/__cb20120816162009/mario/images/thumb/1/15/MarioNSMB2.png/200px-MarioNSMB2.png");
            final ImageView img2 = new ImageView("http://img2.wikia.nocookie.net/__cb20120518002849/mario/images/thumb/7/78/Tanooki_Mario_Artwork_-_Super_Mario_Bros._3.png/180px-Tanooki_Mario_Artwork_-_Super_Mario_Bros._3.png");
    
            final FlipView flipPane = new FlipView(img1, img2);
    
            stackPane.setOnMouseClicked(new EventHandler<MouseEvent>() {
    
                @Override public void handle(final MouseEvent arg0) 
                {
                    flipPane.doFlip();
                }
            });
    
            stackPane.getChildren().setAll(flipPane);
    
            stage.setScene(new Scene(stackPane));
            stage.show();
        }
    
        public static void main(final String[] args)
        {
            launch();
        }
    
        private class FlipView extends Group
        {
            private Node frontNode;
            private Node backNode;
    
            private boolean isFlipped = false;
    
            private SimpleDoubleProperty time = new SimpleDoubleProperty(Math.PI / 2);
    
            private Timeline anim = new Timeline(
    
                    new KeyFrame(Duration.ZERO, new KeyValue(time, Math.PI / 2)),
                    new KeyFrame(Duration.ONE,  new KeyValue(time, - Math.PI / 2)),
                    new KeyFrame(Duration.ONE,  new EventHandler<ActionEvent>() {
    
                        @Override public void handle(final ActionEvent arg0)
                        {
                            isFlipped = !isFlipped;
                        }
                    })
                    );
    
            private FlipView(final Node frontNode, final Node backNode)
            {
                this.frontNode = frontNode;
                this.backNode = backNode;
    
                getChildren().setAll(frontNode, backNode);
    
                frontNode.setEffect(getPT(time.doubleValue()));
                backNode.setEffect(getPT(time.doubleValue()));
    
                frontNode.visibleProperty().bind(time.greaterThan(0));
                backNode.visibleProperty().bind(time.lessThan(0));
            }
    
            private PerspectiveTransform getPT(final double t)
            {
                final double width = 200;
                final double height = 200;
                final double radius = width / 2;
                final double back = height / 10;
    
                return PerspectiveTransformBuilder.create()
                        .ulx(radius - Math.sin(t)*radius)
                        .uly(0 - Math.cos(t)*back)
                        .urx(radius + Math.sin(t)*radius)
                        .ury(0 + Math.cos(t)*back)
                        .lrx(radius + Math.sin(t)*radius)
                        .lry(height - Math.cos(t)*back)
                        .llx(radius - Math.sin(t)*radius)
                        .lly(height + Math.cos(t)*back)
                        .build();
            }
    
            public void doFlip() 
            {
                if (isFlipped)
                {
                    anim.setRate(1.0);
                    anim.setDelay(Duration.ZERO);
                }
                else
                {
                    anim.setRate(-1.0);
                    anim.setDelay(Duration.ONE);
                }
    
                anim.play();
            }
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • GGr*_*rec 7

    经过大量的研发,我已经设法实现了翻转功能,而不是 PerspectiveCamera使用. PerspectiveTransform

    如果您懒得运行此SSCCE,请转到此处查看以下代码如何工作的演示.

    问:但乔治,这与其他方法有什么不同?
    答:嗯,首先:因为您没有使用PerspectiveCamera,如果您在屏幕上有100个翻转图块,则用户的视角不会受到影响.倒数第二个:后面的节点是ALREADY翻转的.所以它没有镜像,它不是旋转,它没有缩放.这是正常的".那不是很好吗?

    干杯.


    import javafx.animation.Interpolator;
    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.effect.PerspectiveTransform;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    /**
     * 
     * @author ggrec
     *
     */
    public class DFXFlipPaneTester extends Application
    {
    
        // ==================== 1. Static Fields ========================
    
        /*
         * Mmm... pie.
         */
        private static final Double PIE = Math.PI;
    
        private static final Double HALF_PIE = Math.PI / 2;
    
        private static final double ANIMATION_DURATION = 10000;
    
        private static final double ANIMATION_RATE = 10;
    
    
        // ====================== 2. Instance Fields =============================
    
        private Timeline animation;
    
        private StackPane flipPane;
    
        private SimpleDoubleProperty angle = new SimpleDoubleProperty(HALF_PIE);
    
        private PerspectiveTransform transform = new PerspectiveTransform();
    
        private SimpleBooleanProperty flippedProperty = new SimpleBooleanProperty(true);
    
    
        // ==================== 3. Static Methods ====================
    
        public static void main(final String[] args)
        {
            Application.launch(args);
        }
    
    
        // ==================== 5. Creators ====================
    
        @Override
        public void start(final Stage primaryStage) throws Exception
        {
            primaryStage.setScene(new Scene(createFlipPane()));
            primaryStage.show();
        }
    
        private StackPane createFlipPane()
        {
            angle = createAngleProperty();
    
            flipPane = new StackPane();
            flipPane.setPadding(new Insets(30));
    
            flipPane.setMinHeight(500);
            flipPane.setMinWidth(500);
    
            flipPane.getChildren().setAll(createBackNode(), createFrontNode());
    
            flipPane.widthProperty().addListener(new ChangeListener<Number>() {
    
                @Override public void changed(final ObservableValue<? extends Number> arg0, final Number arg1, final Number arg2)
                {
                    recalculateTransformation(angle.doubleValue());
                }
            });
    
            flipPane.heightProperty().addListener(new ChangeListener<Number>() {
    
                @Override public void changed(final ObservableValue<? extends Number> arg0, final Number arg1, final Number arg2)
                {
                    recalculateTransformation(angle.doubleValue());
                }
            });
    
            return flipPane;
        }
    
        private StackPane createFrontNode()
        {
            final StackPane node = new StackPane();
    
            node.setEffect(transform);
            node.visibleProperty().bind(flippedProperty);
    
            node.getChildren().setAll(createButton("Front Button")); //$NON-NLS-1$
    
            return node;
        }
    
        private StackPane createBackNode()
        {
            final StackPane node = new StackPane();
    
            node.setEffect(transform);
            node.visibleProperty().bind(flippedProperty.not());
    
            node.getChildren().setAll(createButton("Back Button")); //$NON-NLS-1$
    
            return node;
        }
    
        private Button createButton(final String text)
        {
            final Button button = new Button(text);
            button.setMaxHeight(Double.MAX_VALUE);
            button.setMaxWidth(Double.MAX_VALUE);
    
            button.setOnAction(new EventHandler<ActionEvent>() {
    
                @Override public void handle(final ActionEvent arg0)
                {
                    flip();
                }
            });
    
            return button;
        }
    
        private SimpleDoubleProperty createAngleProperty()
        {
            // --------------------- <Angle> -----------------------
    
            final SimpleDoubleProperty angle = new SimpleDoubleProperty(HALF_PIE);
    
            angle.addListener(new ChangeListener<Number>() {
    
                @Override public void changed(final ObservableValue<? extends Number> obsValue, final Number oldValue, final Number newValue)
                {
                    recalculateTransformation(newValue.doubleValue());
                }
            });
    
            return angle;
        }
    
        private Timeline createAnimation()
        {
            return new Timeline(
    
                    new KeyFrame(Duration.millis(0),    new KeyValue(angle, HALF_PIE)),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION / 2),  new KeyValue(angle, 0, Interpolator.EASE_IN)),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION / 2),  new EventHandler<ActionEvent>() {
    
                        @Override public void handle(final ActionEvent arg0)
                        {
                            // TODO -- Do they another way or API to do this?
                            flippedProperty.set( flippedProperty.not().get() );
                        }
                    }),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION / 2),  new KeyValue(angle, PIE)),
    
                    new KeyFrame(Duration.millis(ANIMATION_DURATION), new KeyValue(angle, HALF_PIE, Interpolator.EASE_OUT))
    
                    );
        }
    
    
        // ==================== 6. Action Methods ====================
    
        private void flip()
        {
            if (animation == null)
                animation = createAnimation();
    
            animation.setRate( flippedProperty.get() ? ANIMATION_RATE : -ANIMATION_RATE );
    
            animation.play();
        }
    
    
        // ==================== 8. Business Methods ====================
    
        private void recalculateTransformation(final double angle)
        {
            final double insetsTop = flipPane.getInsets().getTop() * 2;
            final double insetsLeft = flipPane.getInsets().getLeft() * 2;
    
            final double radius = flipPane.widthProperty().subtract(insetsLeft).divide(2).doubleValue();
            final double height = flipPane.heightProperty().subtract(insetsTop).doubleValue();
            final double back = height / 10;
    
            /*
             * Compute transform.
             * 
             * Don't bother understanding these unless you're a math passionate.
             * 
             * You may Google "Affine Transformation - Rotation"
             */
            transform.setUlx(radius - Math.sin(angle) * radius);
            transform.setUly(0 - Math.cos(angle) * back);
            transform.setUrx(radius + Math.sin(angle) * radius);
            transform.setUry(0 + Math.cos(angle) * back);
            transform.setLrx(radius + Math.sin(angle) * radius);
            transform.setLry(height - Math.cos(angle) * back);
            transform.setLlx(radius - Math.sin(angle) * radius);
            transform.setLly(height + Math.cos(angle) * back);
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)