JavaFX: анимация на основе функции времени - PullRequest
0 голосов
/ 18 марта 2020

У меня нет MWE, потому что я не уверен, как начать. Я предполагаю, что мой вопрос в основном о том, какие инструменты лучше всего подходят для этой работы.

У меня есть объект, равный Function<Double, VectorXYZ>, который выводит позицию объекта в данный момент времени. Он обрабатывает свою собственную интерполяцию. Мне интересно, есть ли способ обработать функциональность Timeline без необходимости использования KeyFrame s. Я хотел бы иметь возможность играть как вперёд, так и использовать Slider.

. Я думал о наличии DoubleProperty, который каким-то образом связан с Timeline, связанным с Listener. обновляет свойство перевода Group, содержащего объект. Но я не знаю, как go сделать это.

Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 20 марта 2020

Так что да, это был очень неопределенный вопрос, но, как сказал @James_D, AnimationTimer - это инструмент, который я искал. В основном я искал низкоуровневый доступ к анимации l oop, и это, похоже, было именно так. Вот MWE объекта, следующего по некоторому пути через сцену. Он отделяет системное время от времени сцены (сохраняется как DoubleProperty), поэтому его можно приостановить и перезапустить, а также установить время с помощью ползунка.

import com.google.common.base.Function;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.control.Slider;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class AnimationTestApp extends Application {

    private static final double durationSeconds = 5;

    private static final double screenWidthMeters = 10;
    private static final double screenHeightMeters = 10;
    private static final double pixelsPerMeter = 50;

    private static final double squareSizeMeters = 0.5;

    private static final double screenWidthPixels = pixelsPerMeter * screenWidthMeters;
    private static final double screenHeightPixels = pixelsPerMeter * screenHeightMeters;

    private static final double squareSizePixels = pixelsPerMeter * squareSizeMeters;

    private static final double originXPixels = screenWidthPixels/2;
    private static final double originYPixels = screenHeightPixels/2;

    private final Rectangle square = new Rectangle(squareSizePixels, squareSizePixels, Color.RED);

    private long lastTime = -1;

    private boolean isStopped = true;

    private double t = 0;

    private DoubleProperty timeProperty;
    private DoubleProperty timeProperty() {
        if (timeProperty == null) {
            timeProperty = new SimpleDoubleProperty();
            timeProperty.addListener((obs, ov, nv) -> {updateScene();});
        }
        return timeProperty;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
            final SubScene subscene = new SubScene(new Group(square), screenWidthPixels, screenHeightPixels);
            Slider timeSlider = new Slider(0, 5, 1);
            timeSlider.valueProperty().bindBidirectional(timeProperty());

            VBox root = new VBox(timeSlider, subscene);
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();

            AnimationTimer animationTimer = buildTimer();
            handleKeyboard(scene, animationTimer);
    }

    private AnimationTimer buildTimer() {
        AnimationTimer animationTimer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                double elapsedNS = now - lastTime;
                double dt = elapsedNS * 1E-9;
                if (timeProperty().get() + dt > durationSeconds) {
                    stop();
                }
                timeProperty().set(timeProperty().get() + dt);
                updateScene();//timeProperty.get());
                lastTime = now;
            }

            @Override
            public void start() {
                lastTime = System.nanoTime();
                isStopped = false;
                if (timeProperty().get() > durationSeconds) {
                    timeProperty().set(0);
                }
                super.start();
            }

            @Override
            public void stop() {
                isStopped = true;
                super.stop();
            }
        };
        return animationTimer;
    }

    private void updateScene() {
        double t = timeProperty().get();
        Point2D point = positionFunction().apply(t);

        double xPixels = originXPixels + point.getX() * pixelsPerMeter;
        double yPixels = originYPixels + point.getY() * pixelsPerMeter;

        square.setTranslateX(xPixels);
        square.setTranslateY(yPixels);
    }

    private Function<Double, Point2D> positionFunction() {
        double radius = 3;
        double period = 2;
        return (t) -> new Point2D(radius * Math.sin(2*Math.PI*t/period), radius * Math.cos(2*Math.PI*t/period));
    }

    private void handleKeyboard(Scene scene, AnimationTimer timer) {
        scene.setOnKeyPressed((ke) -> {
            if (ke.getCode().equals(KeyCode.SPACE)) {
                if (isStopped) {timer.start();}
                else {timer.stop();}
            }
        });
    }   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...