Animation JavaFX:基于时间函数的动画

Animation JavaFX:基于时间函数的动画,animation,javafx,Animation,Javafx,我没有MWE,因为我不知道如何开始。我想我的问题主要是关于哪种工具最适合这份工作 我有一个对象,相当于一个函数,它输出给定时间对象的位置。它处理自己的插值。我想知道是否有一种方法可以处理时间轴的功能,而不必使用关键帧s。我希望既能向前播放,又能使用滑块 我想拥有一个双重属性,它以某种方式链接到时间线,与一个侦听器关联,该侦听器更新包含对象的组的翻译属性。但我不知道该怎么做 谢谢你的帮助 是的,这是一个非常模糊的问题,但正如@James_D所说,AnimationTimer是我一直在寻找的工具。基

我没有MWE,因为我不知道如何开始。我想我的问题主要是关于哪种工具最适合这份工作

我有一个对象,相当于一个
函数
,它输出给定时间对象的位置。它处理自己的插值。我想知道是否有一种方法可以处理
时间轴
的功能,而不必使用
关键帧
s。我希望既能向前播放,又能使用
滑块

我想拥有一个
双重属性
,它以某种方式链接到
时间线
,与一个
侦听器
关联,该侦听器更新包含对象的
的翻译属性。但我不知道该怎么做


谢谢你的帮助

是的,这是一个非常模糊的问题,但正如@James_D所说,
AnimationTimer
是我一直在寻找的工具。基本上,我是在寻找动画循环的低级访问,而这似乎就是它。这是一个物体的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();}
            }
        });
    }   
}
import com.google.common.base.Function;
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.beans.property.DoubleProperty;
导入javafx.beans.property.SimpleDoubleProperty;
导入javafx.geometry.Point2D;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.SubScene;
导入javafx.scene.control.Slider;
导入javafx.scene.input.KeyCode;
导入javafx.scene.layout.VBox;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Rectangle;
导入javafx.stage.stage;
公共类AnimationTestApp扩展了应用程序{
专用静态最终双持续时间秒=5;
专用静态最终双屏幕宽度计=10;
专用静态最终双屏幕高度计=10;
专用静态最终双像素测光仪=50;
专用静态最终双平方尺寸计=0.5;
专用静态最终双屏幕宽度像素=像素计*屏幕宽度计;
专用静态最终双屏幕高度像素=像素计*屏幕高度计;
专用静态最终双平方尺寸表像素=像素表*平方尺寸表;
私有静态最终双原点像素=屏幕宽度像素/2;
私有静态最终双原始像素=屏幕高度像素/2;
私有最终矩形正方形=新矩形(squareSizePixels,squareSizePixels,Color.RED);
私有长lastTime=-1;
私有布尔值=true;
私人双t=0;
私有财产;
私有DoubleProperty timeProperty(){
if(timeProperty==null){
timeProperty=新的SimpleDupleProperty();
addListener((obs,ov,nv)->{updateScene();});
}
返回时间属性;
}
@凌驾
public void start(Stage primaryStage)引发异常{
最终亚场景亚场景=新亚场景(新组(正方形)、屏幕宽度像素、屏幕高度像素);
滑块时间滑块=新滑块(0,5,1);
timeSlider.valueProperty().bindBidirectional(timeProperty());
VBox根=新的VBox(时间滑块,子场景);
场景=新场景(根);
初级阶段。场景(场景);
primaryStage.show();
AnimationTimer AnimationTimer=buildTimer();
手持键盘(场景、动画计时器);
}
私有AnimationTimer buildTimer(){
AnimationTimer AnimationTimer=新建AnimationTimer(){
@凌驾
公共无效句柄(长){
双elapsedNS=现在-上次;
双dt=elapsedNS*1E-9;
if(timeProperty().get()+dt>durationSeconds){
停止();
}
timeProperty().set(timeProperty().get()+dt);
updateScene();//timeProperty.get());
上次=现在;
}
@凌驾
公开作废开始(){
lastTime=System.nanoTime();
isStopped=false;
if(timeProperty().get()>durationSeconds){
timeProperty().set(0);
}
super.start();
}
@凌驾
公共停车场(){
isStopped=true;
super.stop();
}
};
返回动画定时器;
}
私有void updateScene(){
双t=timeProperty().get();
点2D点=位置函数()。应用(t);
双X像素=原始X像素+点.getX()*像素计;
双像素=原始像素+点.getY()*像素测光仪;
正方形。setTranslateX(x像素);
正方形。setTranslateY(像素);
}
私有函数positionFunction(){
双半径=3;
双周期=2;
return(t)->新点2d(radius*Math.sin(2*Math.PI*t/周期)、radius*Math.cos(2*Math.PI*t/周期));
}
专用void手柄键盘(场景、动画计时器){
场景。设置键按下((ke)->{
if(ke.getCode().equals(KeyCode.SPACE)){
if(isStopped){timer.start();}
else{timer.stop();}
}
});
}   
}

你的问题很模糊。要么是a要么应该有效。是的,对不起。我想AnimationTimer绝对是我想要的。我需要一些比动画或时间线更低级的东西。我将组合一个2D MWE来说明我试图实现什么,并用它来回答问题。如果它应该无限期运行,可能是
AnimationTimer
,或者
Transition
,如果它运行了固定数量的t